If you are manipulating strings that is going to be faster to do on a microprocessor than in hardware. However, for FIX you aren't really dealing with strings so much as you are dealing with numbers. Sure the fields are ASCII but you need to convert a lot of them from ASCII to numbers to make any sense of them (e.g. volumes).
I'm not sure that there are any Verilog libraries that will help you with string manipulations but basically, a Verilog compiler can understand ASCII and convert it to its bit representation, e.g. see this answer to Assign ASCII character to wire in Verilog.
- Is there a more elegant way I can have a simple logic [31:0] variable that can be easily referred to by various subsets of its wires without going through all of this verbose rigamarole?
- Is there a syntax I can use with Quartus II and ModelSim that allows me to avoid having yet another extra variable when sending the struct instruction_r (or i or j) to a module that expects a logic [31:0]?
The answer to both is yes. Simple data types such as logic [31:0]
and struct packed {...}
can be directly assigned; casting isn't necessary especially if they are the same width.
Since everything is the same size (32 bits), direct assignment is allowed (example1):
instruction_r instr_r;
instruction_i instr_i;
instruction_j instr_j;
floper #(32) instruction_reg_r(.en(c_irwrite), .d(readdata), .q(instr_r), .* );
always_comb begin
instr_i = instr_r;
instr_j = instr_r;
end
The curly brackets ({}
) can even be used (example2):
logic [5:0] op;
logic [25:0] addr;
logic [4:0] rs, rt;
logic [15:0] imm;
logic [4:0] rd, shamt;
logic [5:0] funct;
floper #(32) instruction_reg_r(.en(c_irwrite), .d(readdata), .q({op,addr}), .* );
always_comb begin
{rs,rt,rd,shamt,funct} = addr;
imm = {rd,shamt,funct};
end
Another approach is to use type parameters. See IEEE Std 1800-2012 § 6.20.3 Type parameters. In this case change the definition of floper
to:
module floper #(parameter WIDTH = 8, parameter type INSTR_TYPE = logic[WIDTH-1:0] )
(input logic clk, reset, en,
input logic [WIDTH-1:0] d,
output INSTR_TYPE q);
// ...
endmodule
Then update the parameter value in the instantiations of floper
. example3:
instruction_r instr_r;
instruction_i instr_i;
instruction_j instr_j;
floper #(32,instruction_r) instruction_reg_r(.en(c_irwrite), .d(readdata), .q(instr_r), .* );
floper #(32,instruction_i) instruction_reg_i(.en(c_irwrite), .d(readdata), .q(instr_i), .* );
floper #(32,instruction_j) instruction_reg_j(.en(c_irwrite), .d(readdata), .q(instr_j), .* );
Streaming operators ({<<{}}
and {>>{}}
) are needed when translating between packed/unpacked values, see IEEE Std 1800-2012 § 11.4.14 Streaming operators, Casting is required for assignments that do not have a 1-to-1 relationship. Casting can also be used for tuncating or padding which is useful for avoiding size mismatch warnings. IEEE Std 1800-2012 § 6.24 Casting a full description and examples.
Best Answer
As I understand it, hardly anything in SystemVerilog is synthesisable; it's intended for use in testbenches and simulations.