Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Assigning value to string in VHDL is generating size mismatch error

Status
Not open for further replies.

matrixofdynamism

Advanced Member level 2
Joined
Apr 17, 2011
Messages
593
Helped
24
Reputation
48
Reaction score
23
Trophy points
1,298
Activity points
7,681
String in VHDL is declared as a character array. Thus, in my case I have declared a string that can contain the largest string assigned to it in a select case construct:

So I have: variable instr_str : string (1 to 4); and then assigning value to it in case statement.

case instr(5 downto 0) is
when alu_add =>
instr_str := "add";
when alu_sub =>
instr_str := "sub";
when alu_and =>
instr_str := "and";
when alu_or =>
instr_str := "or";
when alu_xor =>
instr_str := "xor";
when alu_nor =>
instr_str := "nor";
when others =>
end case;

When I compile the file I get a list of warning messages like:
# ** Warning: [14] /Documents/MIPS/cpu_defs.vhdl(75): (vcom-1272) Length of expected is 4; length of actual is 3.

When I run it I get this error:
# ** Fatal: (vsim-3420) Array lengths do not match. Left is 4 (1 to 4). Right is 3 (1 to 3).

Is there really no around this other than assign a string of 4 characters to instr_str everytime? This doesn't look right.
 

I assume you're using enumeration for instr such that


Code VHDL - [expand]
1
type instr is (alu_add, alu_sub, alu_and, alu_or, alu_xor, alu_nor);




the warning on line (75) I assume relates to


Code VHDL - [expand]
1
instr_str := "or";



This is because your or is only 3 char long
'o' and 'r' & some newline nullifying char

Regards,
Wes

- - - Updated - - -

You could try unconstrained arrays (<>)
 
I have declared the alu_add, alu_sub, alu_and, alu_or, alu_xor & alu_nor as constants even though I am thinking of changing it to enum. You have understood the problem correctly. Usually in other languages I would expect to declare a string and assign strings of variable length to it. However, in VHDL here I find that if I declare strings I must give a length for them within the declaration and later everything I assign to it must be of this length. If it is less than the assigned length, then I will encounter this error that I see now.

Why can't I just declare a string in VHDL and then assign variable length strings to it as long as they are not bigger than the upper bound of the string declaraction?
 

Why don't you use some encoding for the operations alu_add(000), alu_sub(001), alu_and(010), alu_or(011), alu_xor(100), alu_nor(101) and then check the values inside the case statement.
 
String in VHDL is declared as a character array. Thus, in my case I have declared a string that can contain the largest string assigned to it in a select case construct:

So I have: variable instr_str : string (1 to 4); and then assigning value to it in case statement.

case instr(5 downto 0) is
when alu_add =>
instr_str := "add";
when alu_sub =>
instr_str := "sub";
when alu_and =>
instr_str := "and";
when alu_or =>
instr_str := "or";
when alu_xor =>
instr_str := "xor";
when alu_nor =>
instr_str := "nor";
when others =>
end case;
Since you've defined 'instr_str' to be a four character string, you can't assign just three characters to it as you're doing in almost all of your assignments.

It's also not clear why 'instr' is already a string and why you're looking at only the '5 downto 0' range of that string and just what are the definitions of 'alu_add', 'alu_sub', etc. If they are really already strings, what is wrong with using them 'as-is'?

I'm guessing (possibly incorrectly) that 'alu_add', 'alu_sub' are actually enumerations of a type that you have created. I'm also guessing that the reason that you're converting your enums to a string is for output to the console or a file or something like that. If so, may I suggest that a better way to do that is to create a 'to_string' function that returns the string.

Example:
Code:
function to_string(Instr:  t_INST_TYPE) return String is
begin
    case Instr is
        when alu_add => return("add");
        when alu_sub => return("sub");
        when alu_and => return("and");
        when alu_or => return("or");
        when alu_xor => return("xor");
        when alu_nor => return("nor");
        when others => return("");
    end case;
end function to_string;
Then just use this function where needed. Example:
report "The instruction is " & to_string(Instr);

That way you're never having to pre-define some string length avoiding the whole problem of assigning different length strings and having these types of issues.

Kevin Jennings

- - - Updated - - -

Why can't I just declare a string in VHDL and then assign variable length strings to it as long as they are not bigger than the upper bound of the string declaraction?
The short answer is because the language does not allow you to do this.

The somewhat longer answer as to why the language does not allow this is that when you assign some shorter length string to a longer string then what you're really doing is only assigning to a subset of that longer string, you're not assigning to the whole string. You may think this is overly picky just for a string, but to VHDL strings are just another type and it treats all types equally.

If you insist on working with strings, one way around it is to create a function (maybe call it 'pad_string') that takes as input arguments the shorter length string and the length that you would like it to be and the function returns a string of that length. This gets clunky quickly since you now have to decide what to pad it with and you're always having to pass in the argument to the function that tells it the length you want out (much like the to_unsigned function in ieee.numeric_std). A better approach to the whole problem is outlined in my earlier post.

Kevin Jennings
 
OK, this does solve my problem. I have realized my folly. At present this is what I have and it must now be changed into an enumerated type:

-- constants for the alu_func;
constant alu_add : std_logic_vector(5 downto 0) := "100000";
constant alu_sub : std_logic_vector(5 downto 0) := "100010";
constant alu_and : std_logic_vector(5 downto 0) := "100100";
constant alu_or : std_logic_vector(5 downto 0) := "100101";
constant alu_xor : std_logic_vector(5 downto 0) := "100110";
constant alu_nor : std_logic_vector(5 downto 0) := "100111";

So this function analyzes a 32 bit binary word representing a MIPS instruction. First it looks at the opcode which is upper 6 bits. If the opcode is "000000" then the lower 6 bits determine what type of arithmatic-logic function is present in the instruction. This function shall ultimately print the assembly version actual instruction into a file/transcript. Thus when the value 00000010010101001011100000100100 is read in from file and this function is called with it, the transcript window must show "instruction is: and $s2, $s4, $s7".

I will now change the constants to enum and use the image attribute with the enum type which will simplify things. The idea you have given me is actually even better for my situation.
 

OK, this does solve my problem. I have realized my folly. At present this is what I have and it must now be changed into an enumerated type

In that case, I'd suggest a 'From_String' function like the following:

Code:
function From_String(S: String(5 downto 0)) return t_INST_TYPE is
begin
    case S is 
        when "100000" => return(alu_add);
        when "100010" => return(alu_sub);
        when "100100" => return(alu_and);
        when "100101" => return(alu_or);
        when "100110" => return(alu_xor);
        when "100111" => return(alu_nor);
        when others => report "Unexpected instruction " & image(S) severity ERROR; return([COLOR=#FF0000]alu_add[/COLOR]); -- Still need to return 'something' after the assertion
   end case;
end function From_String;

Kevin Jennings
 
I hope this is the last question I have to ask in this thread:

This is what I have in the architecture of the testbench
type opcode is (alu_add, alu_sub, alu_and, alu_or, alu_xor, alu_nor);
attribute opcode_encoding : string;
attribute opcode_encoding of opcode: type is "100000 100010 100100 100101 100110 100111";

Having applied the encoding. How can I print the encoded value? e.g if I set
variable myopcode : opcode := alu_sub;
Now how do I print the encoded value of myopcode which is "100010" in this case? In the predefined attributes list I find image, value, pos, val among others. However, it seems that there is no attribute that will simply print the encoded value.

Please do not be confused. I am merely trying to understand how the enum types and strings work here.
 

With a situation like this where the op-code encodings are fixed and will never change, I would do it the first way you had it - define the opcodes as constants, and have a "to_string" function to get you the real name of the opcode.
 
I'd be keen to see an answer to #8.

It'd be nice to see the bit vector being displayed when you specify a type.

I know attribute opcode_encoding of opcode: type is "100000 100010 100100 100101 100110 100111"; is used for FSM see https://www.doulos.com/knowhow/fpga/fsm_optimization/

However...how to do you then print the string? Can modelsim handle this?

x <= alu_xor;
wait for 1 ns;
write(line, opcode'image(x)) -- ...just prints the text of what state it's in. (alu_xor)


How to get 'val or value which should be
100110
 
This is what I have in the architecture of the testbench
type opcode is (alu_add, alu_sub, alu_and, alu_or, alu_xor, alu_nor);
attribute opcode_encoding : string;
attribute opcode_encoding of opcode: type is "100000 100010 100100 100101 100110 100111";

Having applied the encoding. How can I print the encoded value? e.g if I set
variable myopcode : opcode := alu_sub;
Now how do I print the encoded value of myopcode which is "100010" in this case?
Personally, I wouldn't use attributes, what I would do is define a 'to_unsigned' function (or 'to_std_ulogic_vector') that converts the enum into an unsigned or a std_ulogic_vector. Then to print it out you can use image() or heximage(). The reason for preferring the two step is that the 'to_unsigned' and 'to_std_ulogic_vector' functions will typically have usages outside of just converting them into a printable string.

Example:

Code:
function to_std_ulogic_vector(L: t_INST_TYPE ) return std_ulogic_vector is
    variable RetVal:  std_ulogic_vector(5 downto 0);
begin
    case L is
        when alu_add => RetVal := "100000";
        when alu_sub => RetVal := "100010";
        when alu_and => RetVal := "100100";
        when alu_or => RetVal := "100101";
        when alu_xor => RetVal := "100110";
        when alu_nor => RetVal := "100111";
    end case;
    return(RetVal);
end function to_std_ulogic_vector;

Kevin Jennings

- - - Updated - - -

I'd be keen to see an answer to #8.
See #11

It'd be nice to see the bit vector being displayed when you specify a type.
Displayed where? You can convert it into a printable string, but you can't 'display' the attribute in a waveform window if that's your question. However, in your waveform window Modelsim will already display 'opcode' as the enumeration (i.e. 'alu_add', alu_xor', etc.) which is far better than displaying the hex or binary counterpart.

I know attribute opcode_encoding of opcode: type is "100000 100010 100100 100101 100110 100111"; is used for FSM see https://www.doulos.com/knowhow/fpga/fsm_optimization/

However...how to do you then print the string? Can modelsim handle this?
See post #11

Code:
x <= alu_xor;
wait for 1 ns;
write(line, opcode'image(x)) -- ...just prints the text of what state it's in. (alu_xor)
Code:
write(line, heximage(to_std_ulogic_vector(opcode))); -- I have 'image' and 'heximage' functions in a library of commonly used 'stuff'

How to get 'val or value which should be 100110
But 100110 is not the 'value' of opcode, it is just an attribute of opcode. The 'value' is 'alu_xor'.

Kevin Jennings
 
OK, I did realize eventually that using constants is the better tradeoff here since I could not find how to ensure that what I put in as attribute will actually be used by the synthesis tool also. Now I have understood that '100110 is not the 'value' of opcode, it is just an attribute of opcode. The 'value' is 'alu_xor'.' Yes. Got it.

This post has been quite helpful. I have finally written functions which return string value and do the following things: return register name from a 5 bit std_logic_vector passed to it as parameter this name could be between 3 to 5 characters long, return insturction name which depends on opcode which is top 6 bits of the instruction and if opcode is "000000" than on funct which is bottom 6 bits of the instruction, return assembly version of the instruction as string by using the previous three functions mentioned. The code is clean and not littered with throngs of select case and if statements. Thank you sooo much for your help Kevin.
 

This thread has been very useful & productive.

K-J, what does heximage do that
Code:
hwrite(line, to_std_ulogic_vector(opcode));
wouldn't do?


Also Matrix...please mark thread as solved if you've got the answers you were after
 

heximage I assume returns a string, rather than writing directly to a line. So you could add it in as part of another line when writing to file:

Code:
write(l, "you can do this (" & heximage(to_std_logic_vector(opcode)) & ") in 1 line of code" & LF);

--instead of 

write(l, string'("you can do this(") );
hwrite(l, to_std_ulogic_vector(opcode));
write(l, string'(") in 3 lines of code"));

As a side note:

to avoid having to use string'("this is a string") all the time, you can do this instead

Code:
write(l, "" & "This is a string");
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top