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
|
/*
* This is very similar to design/slave.v, although with 1 important difference
* - it's meant to be synthesizable (and use iCE40HX8K's embedded RAM).
*/
/*
* | *WISHBONE DATASHEET* |
* |---------------------------------------------------------------------------|
* | *Description* | *Specification* |
* |---------------------------------+-----------------------------------------|
* | General description | (MEMORY_BLOCKS*256)x16-bit memory core |
* |---------------------------------+-----------------------------------------|
* | Supported cycles | SLAVE, pipelined READ/WRITE |
* |---------------------------------+-----------------------------------------|
* | Data port, size | 16-bit |
* | Data port, granularity | 16-bit |
* | Data port, maximum operand size | 16-bit |
* | Data transfer ordering | Big endian and/or little endian |
* | Data transfer ordering | Undefined |
* | Address port, size | $clog2(MEMORY_BLOCKS) + 8 bits |
* |---------------------------------+-----------------------------------------|
* | Clock frequency constraints | NONE (determined by memory primitive, |
* | | about 100 MHz in case of iCE40HX8K) |
* |---------------------------------+-----------------------------------------|
* | | *Signal name* | *WISHBONE Equiv.* |
* | |------------------+----------------------|
* | | ACK_O | ACK_O |
* | | ADR_I | ADR_I() |
* | Supported signal list and cross | CLK_I | CLK_I |
* | reference to equivalent | DAT_I | DAT_I() |
* | WISHBONE signals | DAT_O | DAT_O() |
* | | STB_I | STB_I |
* | | WE_I | WE_I |
* | | RST_I | RST_I |
* | | STALL_O | STALL_O |
* |---------------------------------+-----------------------------------------|
* | | Circuit assumes the use of synchronous |
* | Special requirements | RAM with asynchronour read |
* | | inreffable by synthesis software. |
* |---------------------------------+-----------------------------------------|
* | | The MEMORY_BLOCKS parameter can be used |
* | | to decide the size of the memory. |
* | Additional information | Single block contains 256 16-bit |
* | | words. Address width changes |
* | | accordingly to memory size. |
*/
`default_nettype none
`define ADDR_WIDTH ($clog2(MEMORY_BLOCKS) + 8)
module embedded_bram_slave
#(
parameter MEMORY_BLOCKS = 1, /* 1 block stores 256 16-bit words */
parameter WORDS_TO_INITIALIZE = 0,
parameter INITIAL_CONTENTS_FILE = "some_file.mem"
)
(
output wire ACK_O,
input wire CLK_I,
input wire [`ADDR_WIDTH - 1:0] ADR_I,
input wire [15:0] DAT_I,
output wire [15:0] DAT_O,
input wire RST_I,
input wire STB_I,
input wire WE_I,
output wire STALL_O
);
reg [15:0] memory [256 * MEMORY_BLOCKS - 1 : 0];
generate
if (WORDS_TO_INITIALIZE) begin
initial
$readmemb(INITIAL_CONTENTS_FILE, memory, 0, WORDS_TO_INITIALIZE - 1);
end else begin
always @ (posedge CLK_I) begin
if (!RST_I && STB_I && WE_I)
memory[ADR_I] <= DAT_I;
end
end
endgenerate
reg [15:0] output_data;
reg ack;
assign DAT_O = output_data;
assign ACK_O = ack;
assign STALL_O = 0;
always @ (posedge CLK_I) begin
if (RST_I) begin
ack <= 0;
end else begin
ack <= STB_I;
output_data <= memory[ADR_I];
end
end
endmodule // embedded_bram_slave
|