One of the "nice" ways of flattening an array is to choose an array size where the edge lengths are powers of 2. For example, you have sizes 108 and 28 bits. If you round those up to 128 and 32 bits, then you can concatenate the bit addresses together to get a "flat" array.
For example, say x is the 32 bit address and y is 128 bit address,
square[x][y]
maps to flat[x + y << 32]
To work this out in verilog, you can loop through x and y in a nested fashion, and your new flat data address is {x,y} or {y,x} depending if you want your data row-wise or column-wise.
The other side is just a matter of reversing the process. It's trivial to pad the data with zeros where necessary, and it seems you are doing some padding in any case because your row lengths aren't the same.