File: mem_sim.v

package info (click to toggle)
yosys 0.52-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 69,796 kB
  • sloc: ansic: 696,955; cpp: 239,736; python: 14,617; yacc: 3,529; sh: 2,175; makefile: 1,945; lex: 697; perl: 445; javascript: 323; tcl: 162; vhdl: 115
file content (111 lines) | stat: -rw-r--r-- 3,709 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// The MLAB
// --------
// In addition to Logic Array Blocks (LABs) that contain ten Adaptive Logic
// Modules (ALMs, see alm_sim.v), the Cyclone V also contains
// Memory/Logic Array Blocks (MLABs) that can act as either ten ALMs, or utilise
// the memory the ALM uses to store the look-up table data for general usage,
// producing a 32 address by 20-bit block of memory. MLABs are spread out
// around the chip, so they can be placed near where they are needed, rather than
// being comparatively limited in placement for a deep but narrow memory such as
// the M10K memory block.
//
// MLABs are used mainly for shallow but wide memories, such as CPU register
// files (which have perhaps 32 registers that are comparatively wide (16/32-bit))
// or shift registers (by using the output of the Nth bit as input for the N+1th
// bit).
//
// For historical reasons a MISTRAL_MLAB cell represents a 32 address by 1-bit cell,
// and 20 of them represent a physical MLAB.
//
// How the MLAB works
// ------------------
// MLABs are poorly documented, so the following information is based mainly
// on the simulation model and my knowledge of how memories like these work.
// Additionally, note that the ports of MISTRAL_MLAB are the ones auto-generated
// by the Yosys `memory_bram` pass, and it doesn't make sense to me to use
// `techmap` just for the sake of renaming the cell ports.
//
// The MLAB can be initialised to any value.
//
// The MLAB takes in data from A1DATA at the rising edge of CLK1, and if A1EN
// is high, writes it to the address in A1ADDR. A1EN can therefore be used to
// conditionally write data to the MLAB.
//
// Simultaneously, the MLAB reads data from B1ADDR, and outputs it to B1DATA,
// asynchronous to CLK1 and ignoring A1EN. If a synchronous read is needed
// then the output can be fed to embedded flops.

// The vendor sim model outputs 'x for a very short period (a few
// combinational delta cycles) after each write. This has been omitted from
// the following model because it's very difficult to trigger this in practice
// as clock cycles will be much longer than any potential blip of 'x, so the
// model can be treated as always returning a defined result.

(* abc9_box, lib_whitebox *)
module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN,
    (* clkbuf_sink *) input CLK1,
    input [4:0] B1ADDR, output B1DATA);

reg [31:0] mem = 32'b0;

`ifdef cyclonev
specify
    $setup(A1ADDR, posedge CLK1, 86);
    $setup(A1DATA, posedge CLK1, 86);
    $setup(A1EN, posedge CLK1, 86);

    (B1ADDR[0] => B1DATA) = 487;
    (B1ADDR[1] => B1DATA) = 475;
    (B1ADDR[2] => B1DATA) = 382;
    (B1ADDR[3] => B1DATA) = 284;
    (B1ADDR[4] => B1DATA) = 96;
endspecify
`endif

always @(posedge CLK1)
    if (A1EN) mem[A1ADDR] <= A1DATA;

assign B1DATA = mem[B1ADDR];

endmodule

// The M10K
// --------
// TODO

module MISTRAL_M10K(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);

parameter INIT = 0;

parameter CFG_ABITS = 10;
parameter CFG_DBITS = 10;

(* clkbuf_sink *) input CLK1;
input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
input [CFG_DBITS-1:0] A1DATA;
input A1EN, B1EN;
output reg [CFG_DBITS-1:0] B1DATA;

reg [2**CFG_ABITS * CFG_DBITS - 1 : 0] mem = INIT;

`ifdef cyclonev
specify
    $setup(A1ADDR, posedge CLK1, 125);
    $setup(A1DATA, posedge CLK1, 97);
    $setup(A1EN, posedge CLK1, 140);
    $setup(B1ADDR, posedge CLK1, 125);
    $setup(B1EN, posedge CLK1, 161);

    if (B1EN) (posedge CLK1 => (B1DATA : A1DATA)) = 1004;
endspecify
`endif

always @(posedge CLK1) begin
    if (!A1EN)
        mem[(A1ADDR + 1) * CFG_DBITS - 1 : A1ADDR * CFG_DBITS] <= A1DATA;

    if (B1EN)
        B1DATA <= mem[(B1ADDR + 1) * CFG_DBITS - 1 : B1ADDR * CFG_DBITS];
end

endmodule