VHDL STD_LOGIC_VECTOR Wildcard Values - wildcard

I've been trying to write a Finite State Machine in VHDL code for a simple 16-bit processor I'm implementing on an Altera DE1 board. In the Finite State Machine, I have a CASE statement that handles the different 16-bit instructions, which are brought into the FSM by a 16-bit STD_LOGIC_VECTOR. However, I'm having a little trouble in the decode state where the Finite State Machine decodes the instruction. One of the instructions is an ADD which takes two registers as operands and a third as the destination register. However, I also have an ADD instruction which takes a register and a 5-bit immediate value as operands and a second register for the destination. My problem is that in the CASE statement, I need to be able to differentiate between the two different ADD instructions. So, I thought that if I use wildcard values like "-" or "X" in the CASE statement, I would be able to differentiate between the two with just two cases instead of listing all of the possible register/immediate value combinations. For example:
CASE IR IS --(IR stands for "Instruction Register")
WHEN "0001------0-----" => (Go to 3-register add);
WHEN "0001------1-----" => (Go to 2-register/immediate value add);
WHEN OTHERS => (Do whatever);
END CASE;
These aren't the only two instructions I have, I just put these two to make this post a little shorter. When I compile and run this code, the processor stops executing when it gets to the "decode" state. Also, Quartus gives many, many warnings saying things like "VHDL choice warning at LC3FSM.vhd(37): ignored choice containing meta-value ""0001------0-----"""
I am at a loss as to how to go about accomplishing this. I REALLY do not and probably don't need to define every single 16-bit combination, and I hope there's a way to use wildcards in a STD_LOGIC_VECTOR to minimize the number of combinations I will have to define.
Does anybody know how to accomplish this?
Thanks

That can't be done unfortunately. Rather unexpectedly for most users, the comparison operator = and the case comparison perform a literal comparison. This is because the std_logic type is just a set of characters, which happen to perform like logic values due to the way other functions (eg and and or) are defined.
VHDL-2008 introduces a new case statement case? which performs as you expect - you'll need to tell your compiler to operate in VHDL 2008 mode. In addition, there is a ?= operator in VHDL 2008 which compares two values, taking account of -s.
If you are lumbered with a compiler which still doesn't support VHDL 2008, complain to the supplier. There is also a std_match function allows you to perform comparisons in older VHDL revisions, but nothing that I am aware to make the case statement work that way.

Assuming you don't need the other bits in the instruction you could hack your way around this by masking the other bits with a pre-check process. (Or just ensure the other bits are reset when you write the instruction?)
This really is a bit of a hack.
assuming IR is stored as a variable
if IR(15 downto 12) == "0001" then
IR := IR_in(15 downto 12) & "0000000" & IR_in(5) & "00000";
else
IR := IR_in
end if;
CASE IR IS --(IR stands for "Instruction Register")
WHEN "0001000000000000" => (Go to 3-register add);
WHEN "0001000000100000" => (Go to 2-register/immediate value add);
WHEN OTHERS => (Do whatever);
END CASE;
Alternatively assuming your instruction is cleverly thought out (are the first four bits the command word or something along those lines?) you could do nested case statements and do the differentiation as needed in those sub blocks.

Related

How can the processor discern a far return from a near return?

Reading Intel's big manual, I see that if you want to return from a far call, that is, a call to a procedure in another code segment, you simply issue a return instruction (possibly with an immediate argument that moves the stack pointer up n bytes after the pointer popping).
This, apparently, if I'm interpreting things correctly, is enough for the hardware to pop both the segment selector and offset into the correct registers.
But, how does the system know that the return should be a far return and that both an offset AND a selector need to be popped?
If the hardware just pops the offset pointer and not the selector after it, then you'll be pointing to the right offset but wrong segment.
There is nothing special about the far return command compared to the near return version.
They both look identical as far as I can tell.
I assume then that the processor, perhaps at the micro-architecture level, keeps track of which calls are far and which are close so that when they're returned from, the system knows how many bytes to pop and where to pop them (pointer registers and segment selector registers).
Is my assumption correct?
What do you guys know about this mechanism?
The processor doesn't track whether or not a call should be far or near; the compiler decides how to encode the function call and return using either far or near opcodes.
As it is, FAR calls have no use on modern processors because you don't need to change any segment register values; that's the point of a flat memory model. Segment registers still exist, but the OS sets them up with base=0 and limit=0xffffffff so just a plain 32-bit pointer can access all memory. Everything is NEAR, if you need to put a name on it.
Normally you just don't even think about segmentation so you don't actually call it either. But the manual still describes the call/ret opcodes we use for normal code as the NEAR versions.
FAR and NEAR were used on old 86 processors, which used a segmented memory model. Programs at that time needed to choose what kind of architecture they wished to support, ranging from "tiny" to "large". If your program was small enough to fit in a single segment, then it could be compiled using NEAR calls and returns exclusively. If it was "large", the opposite was true. For anything in between, you had power to choose whether local functions needed to be able to be either callable/returnable from code in another segment.
Most modern programs (besides bootloaders and the like) run on a different construct: they expect a flat memory model. Behind the scenes the OS will swap out memory as needed (with paging not segmentation), but as far as the program is concerned, it has its virtual address space all to itself.
But, to answer your question, the difference in the call/return is the opcode used; the processor obeys the command given to it. If you mistake (say, give it a FAR return opcode when in flat mode), it'll fail.

VHDL Order of options in case statement

I am writing a FSM in VHDL for a basic CPU control unit. In a process I use case statement to decode instruction code. My question is, does the order of the when "..." => statements matter/change anything, or will the inferred "circuit" be the same? I suspect it will, but I want to be sure.
I'd rather have the cases in order that is easy to orientate in, not ordered by value.
The order of the when "..." => statements cannot possibly matter/change anything in simulation or synthesis because in VHDL they must be mutually exclusive.
The order does not have any effect.
case State is
when A => ...
when B => ...
end case;
is identical to
case State is
when B => ...
when A => ...
end case;
I suppose some synthesis tools could produce different state encoding based on the order, but this should not be something that you should have to worry about.
There is no difference in your order because the synthesis tool will collect all branches of case statement and put them in one big multiplexer. The multiplexer will evaluate on your different branch conditions (obviously your inputs).
Don't forget when others => statement ;)
More information about "case statement":
http://www.vhdl-online.de/courses/system_design/vhdl_language_and_syntax/sequential_statements/case_statement

Ada pragma Pack or Alignment attribute for Records?

Having just discovered alignment issues for the first time I am unsure on which method is the best/safest way to deal with them. I have a record which I am serialising to send over a Stream and vice-versa so it must meet the interface spec and contain no padding.
Given the example record:
type MyRecord is record
a : Unsigned_8;
b : Unsigned_32;
end record;
This by default would require 8 bytes but I am able to remove packing using 2 methods:
for MyRecord'Alignment use 1;
or
pragma Pack (MyRecord);
I have found a few questions relating to C examples but haven't been able to find a clear answer on which method is the most appropriate, how to determine which method to use or if they are equivalent?
UPDATE
When I tried both on my 'real' code rather than a basic example I found that the Alignment attribute achieved what I was looking for. pragma Pack significantly reduced the size, not confirmed but I assume it has packed the many enumerated types I'm using, overriding the 'Size use 8 attribute applied to each type.
For Streams you could leave MyRecord without any representation clauses and use the default MyRecord’Write and MyRecord’Read; ARM 13.13.2(9) says
For elementary types, Read reads (and Write writes) the number of stream elements implied by the Stream_Size for the type T; the representation of those stream elements is implementation defined. For composite types, the Write or Read attribute for each component is called in canonical order, which is last dimension varying fastest for an array (unless the convention of the array is Fortran, in which case it is first dimension varying fastest), and positional aggregate order for a record.
One possible disadvantage of the GNAT implementation (and maybe of others) is that the ’Write and ’Read calls each end in a call to the underlying network software. Not a problem (aside from possible inefficiency) normally, but if you’re using TCP_NODELAY (or worse, UDP) this is not the behaviour you’re looking for.
Overloading ’Write leads back to your original problem (but at least it’s confined to the overloading procedure, so the rest of your program can deal with properly aligned data).
I’ve used an in-memory stream for this (especially the UDP case); ’Write to the in-memory stream, then send the Stream_Element_Array to the socket. One example is ColdFrame.Memory_Streams (.ads, .adb).
I think you want the record representation clauses, if you want full control:
for MyRecord'Size use 40;
for MyRecord use record
a at 0 range 0 .. 7;
b at 1 range 0 .. 31;
end record;
(or some such, I might have messed up some of the indices here).
NB: edited as per comment by Simon

synthesizable asynchronous fifo design towards an FPGA

I need some advice on how to design an asynchronous FIFO. I understand the meta stability issue when capturing data into a different clock domain, my question is how does using a two flip flop shift register assist in synchronization of write pointer and read pointer values for full and empty flag calculation.
When register captures a data of a different domain there is a possibility it can enter a metastable state and can settle to a unknown value, so how do u effectively resolve this issue.
Thanks
Your read and write pointers need to use gray encoding when transferred from one clock domain to the other. As you should know, only 1 bit of a gray counter is different between two consecutive values. Thus, metastability can affect only the one changing bit. After re-synchronization, the transferred pointer will be either the updated pointer or its previous value.
In either case, this is not a problem and only lead to pessimistic flags/count for your FIFO.
I use regular counter for my read/write pointer, and use the following functions to convert them to gray code. They are in VHDL, but you should get the idea:
function bin_to_gray(a: unsigned) return unsigned is
begin
return a xor ('0' & a(a'left downto 1));
end function bin_to_gray;
function gray_to_bin(a: unsigned) return unsigned is
variable ret : unsigned(a'range);
begin
ret(a'left) := a(a'left);
for i in a'left-1 downto 0 loop
ret(i) := ret(i+1) xor a(i);
end loop;
return ret;
end function gray_to_bin;
Jonathan explained it well.
I would just like to add a few points:
First, in addition to your 2-stage synchronizer registers you must also have a source register.
You can never feed signals from combinational logic into your 2-stage synchronizer, since combinational logic produce glitches.
You must also be aware that Verilog and VHDL has no built-in support for clock domain crossings and metastability.
Even if you create a proper 2-stage synchronizer to transfer the gray coded pointers, there is no guarantee that the synthesis tool does not change your synchronizers in a way which make it ineffective in protecting againsts metastability. Some synthesis tools try to detect synchronizers and leave them alone. Some don't. And in either case, you should not rely on it.
For a completely proper clock domain crossing, you must constrain the synchronizer and the source register using vendor-specific attributes and SDC timing constraints.

Ada array access: Pointer to a specific item within the array, the position being dynamic based on input parameters.

I'm working in Ada95, and I'm having difficulty figuring out pointers.
I have code that looks like the following:
type vector is array (1 .. 3) of integer;
type vector_access is access vector;
my_vec : vector;
procedure test is
pointer : vector_access := my_vec'access;
begin
...
end;
This fails compilation on the definition of pointer, saying
"The prefix to 'ACCESS must be either an aliased view of an object or denote a subprogram with a non-intrinsic calling convention"
If I then change the definition of the vector itself to:
my_vec : aliased vector
it now returns the compiler error:
"The expected type for X'ACCESS, where X denotes and aliased view of an object, must be a general acces type"
At the end of the day what I really need is a pointer to a specific item within the array, the position being dynamic based on input parameters. Can anyone point me in the right direction?
If you're using GNAT, the error message after the "must be a general access type" should have given you the solution:
add "all" to type "vector_access"
defined at line ...
so that you would end up with:
type Vector_Access is access all Vector;
The use of "all" to designate a general access type has to do with dynamic memory allocation pools in Ada. If you don't care about dynamic memory allocation pools, then don't worry about it, and just include "all" in your access type definitions.
I'm not sure if this is part of what you're looking for at the end of the day, but you are aware that in most circumstances Ada's access (pointer) types are used to handle dynamically allocated memory, right?
So instead of pointing my_vec at an aliased variable, you would dynamically allocate it:
Pointer_2_Dynamic : vector_access := new Vector;
This way you can dynamically allocate at runtime the objects you need, and easily handle variably sized ones (though you'd need a different vector definition to accomplish that:
type Dynamic_Vector is array (Natural range <>) of Integer;
type Dynamic_Vector_Access is access Dynamic_Vector;
N : Natural := 10; -- Variable here, but could be a subprogram parameter.
Dyn_Vector : Dynamic_Vector_Access := new Dynamic_Vector(1..N);
OK. Lesson one on Ada for expert Cish coders: Ada parameters are different than Cish parameters. In C, (pre-reference parameters) every single parameter is the equivalent of an Ada 'in' parameter, with an extra proviso that the C compiler must always stupidly pass the entire thing on the stack, no matter how huge it is. So you poor C coders get it nailed into your brains that you never pass large objects into subroutines directly, but always use pointers.
Ada is different. You tell the compiler how you want to access your parameters (read only - 'in', write only - 'out', or read write - 'in out'). However, that has nothing to do with how parameters are passed. The parameter passing mechanisim is up to the compiler, and the compiler will chose the most efficient way to do it. In practice, on nearly all platforms, that means than anything too big for a register will be passed by reference. But this is an implementation detail, and is the compiler's business, not yours. You shouldn't even have to think about it, except in really rare cases.
So grit your teeth and pass that array naked as an in out parameter. Trust me, you'll get to like it.
type vector is array (natural range <>) of integer;
my_vec : vector(1..3);
procedure test (subject : in out vector) is
begin
...
end;
Ada is designed to be quite usable in nearly all cases without needing pointers, and usable in all but a very few very rare cases without needing pointers to stack-allocated objects.
The former is fairly unsafe (dangers from unallocated pointers and memory leaks), and the latter is even more unsafe (stack objects may go out of scope before your pointer does, and even if they don't one little size error can corrupt your entire program). You can still do both in Ada, but unlike many languages it is designed to make unsafe things require a bit more work on your part to do, and make very unsafe things a major PITA to write.
For example, if you'd just dynamically allocate the entire array, you wouldn't have to fool with this aliased and all business. Furthermore, if you just want to pass the array into a subroutine, you could simply pass it as a parameter and you don't even have to fool with the dynamic allocations and deallocations. Again, Ada compilers are smart enough to pass large objects by reference (yes, even if you specified in). This takes an attitude adjustment from C/C++ coders, who are used to having to tell their dumbass compiler not to pass 10meg objects on the stack. You have to learn to let the Ada compiler worry about how to pass your parameters around efficiently, and you can just worry about how to write great code.
Think I found it, for anyone else running into the same issue.
The answer has to do with what specifically is being aliased. The array declaration needs to be:
type vector is array (1 .. 3) of aliased integer;
in order to make sure the integers are stored in memory, and not registers.

Resources