Well say I got 32 outputs from a bunch of ICs sitting on a breadboard. I want to feed these to a new set of ICs on another breadboard. Why can't I just hook up the 24 wires for the first 24 ouputs, and ignore the last 8 outputs? Alternatively, if I got a 32bit adder as one big IC, why can't I simply ignore the pins representing the upper 8 bits? What's wrong with that?
Nothing wrong. But then you need to increment the whole 32 bits counter, and wire to the next circuit only the 24 bits you need. Seems very similar to a typecast, but it's not about changing a data type, it's about rewiring a circuit.
Please put the code of the whole module, so we can discuss it line by line, and make an idea of what is happening under the hood.
The module I copied from some sample code, I just modified the name of it and the text file it reads the data from:
module ROM_SIN_256(
input clk,
input [7:0] addr,
output reg [7:0] dout
);
reg [7:0] memory [0:255];
initial
$readmemh("sin_256.txt", memory);
// synchronous ROM
always @(posedge clk)
dout <= memory[addr];
endmodule
In my top.v file I have this:
reg sin_clk;
reg [7:0] sin_addr;
reg [7:0] sin_val;
always @ (posedge oclk)
/* other code */
ROM_SIN_256 sin_inst(
.clk(sin_clk),
.addr(sin_addr),
.dout(sin_val)
);
This leads to: "ERROR - concurrent assignment to a non-net sin_val is not permitted. VERI-1195 [top.v:78]".
If I change the declaration of "sin_val" to wire [7:0] sin_val;
I don't get an error. What confused me was that dout is declared as "reg", and since I've not yet studied modules in depth I just have an implicit understanding of the syntax. But I think that has more to do with how Verilog works than how the hardware works.
Let's focus only on the registers that gives the error. The toolchain will see in the top.v file you described some registers. A register is built out of D-type flip-flops. A D-type flip-flop is a circuit that, on the rising edge of the clock signal, it copies at the Q outputs what the data present at the D input. Once copied, the flip-flop will memorise the data, and doesn't look at the D input any more until the next rising edge, when it will copy D to Q again, and so on.
The typical D-type flip-flop has some more pins, S and R for (asynchronous) set or reset, non Q, as can be seen in the next hand drawing, or in this (random googled) datasheet in figure 3:
https://assets.nexperia.com/documents/data-sheet/74HC_HCT74.pdf where there are 2 flip-flops in the same case of an IC.
An 8 bit register will be made out of 8 D-type flip-flops (FF), where the clock and the reset inputs are usually connected together. To stay with the breadboard you mentioned, an 8 bit register will be 4 x 7474 ICs, each with 2 flip flops inside AND THE WIRES necessary to build the circuit from the right side of the picture:
Now, let's get back to the FPGA toolchain.
- at some point toolchain reads the line "reg [7:0] sin_val;", take 4 x 7474ICs and insert them in our breadboard
- it continues reading, do some other stuff, and at some points it reads
ROM_SIN_256 sin_inst(
.clk(sin_clk),
.addr(sin_addr),
.dout(sin_val)
);
This is very close to what a macro does for the preprocessor of the C language, but I will be afraid to call it a macro. On short, the toolchain will look in the module file, and start to generate the circuits described in the module. One of the lines inside the module ROM_SIN_256 is "output reg [7:0] dout". This will synthesise yet another 8 bits register.
For our breadboard, the toolchain inserts another 4 IC (meaning another 8 flip-flops). At this point, we have 16 flip flops in 2 x 8 bit registers, one is "sin_val", the other "dout". At this point, the toolchain is left with 3 busses of 8 bits each, databus Z", "databus X", and "databus Y", as seen in the next pic, and doesn't know how to wire them.
My guess is that you probably didn't want yet another register in main.v, the one you created with "reg [7:0] sin_val;".
However, if you wanted it, then you need to instruct the toolchain how to wire it to the outputs of the "dout" register, and keep in mind the sin_val will be filled with data one clock later than dout (assuming they are driven by the same clock).
My point is, in the very beginning, it is very misleading to think of all these as typecasts or macros, or even worst, class instantiation of an object, when in fact we deal here with circuits, wires and clocks.
Very soon you'll get use to it, and you'll naturally start to mix software and hardware design techniques, but for now keep thinking about HDL in terms of circuits.