-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathleiwand_rv32_ram.v
164 lines (142 loc) · 5.24 KB
/
leiwand_rv32_ram.v
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
* This file is part of leiwand_rv32.
* Copyright (c) 2019 Franz Flasch.
*
* leiwand_rv32 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* leiwand_rv32 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with leiwand_rv32. If not, see <https://www.gnu.org/licenses/>.
*/
`timescale 1ns/1ps
`include "helper.v"
//`define INIT_RAM_TOZERO
module leiwand_rv32_ram # (
parameter MEM_WIDTH = 32,
parameter MEM_SIZE = 32
)
(
input i_clk,
input i_rst,
input [(MEM_WIDTH-1):0] i_addr,
input [(MEM_WIDTH-1):0] i_dat,
output [(MEM_WIDTH-1):0] o_dat,
input i_we,
input i_stb,
output o_ack,
input i_cyc,
output o_stall,
input [`HIGH_BIT_TO_FIT(4):0] i_dat_wr_size
);
localparam MEM_HIGH_BIT = `HIGH_BIT_TO_FIT(MEM_SIZE-1);
localparam STATE_INIT = 0;
localparam STATE_IDLE = 1;
localparam STATE_FINISH = 2;
reg [(MEM_WIDTH-1):0] data_out;
reg ack_out;
reg stall_out;
reg tmp_stall;
reg [(MEM_WIDTH-1):0] mem[(MEM_SIZE-1):0];
reg [`HIGH_BIT_TO_FIT(STATE_FINISH):0] internal_state;
wire [MEM_HIGH_BIT:0] addr_index;
`ifdef INIT_RAM_TOZERO
reg [`HIGH_BIT_TO_FIT(MEM_SIZE-1):0] mem_index;
`endif
always @(posedge i_clk) begin
if(i_rst) begin
ack_out <= 0;
stall_out <= 1;
tmp_stall <= 1;
data_out <= 0;
// mem[0] <= 32'h00018637;
// mem[1] <= 32'h00158593;
// mem[2] <= 32'h00c58463;
// mem[3] <= 32'hff9ff06f;
// mem[4] <= 32'h00000593;
// mem[5] <= 32'h00154513;
// mem[6] <= 32'hfedff06f;
// 0x00300613 addi x12 x0 3 li a2, 3
// 0x00158593 addi x11 x11 1 addi a1, a1, 1
// 0x00c58463 beq x11 x12 8 beq a1, a2, toggle
// 0xff9ff06f jal x0 -8 j loop
// 0x00000593 addi x11 x0 0 li a1, 0
// 0x00154513 xori x10 x10 1 xori a0, a0, 1
// 0xfedff06f
internal_state <= STATE_INIT;
`ifdef INIT_RAM_TOZERO
mem_index <= 0;
`endif
end
else begin
case (internal_state)
STATE_INIT: begin
ack_out <= 0;
stall_out <= 1;
tmp_stall <= 1;
data_out <= 0;
`ifdef INIT_RAM_TOZERO
mem[mem_index] = 0;
mem_index = mem_index + 1;
if(mem_index >= (MEM_SIZE-2)) begin
/* switch to next state after initialization */
internal_state <= STATE_IDLE;
end
`else
internal_state <= STATE_IDLE;
`endif
end
STATE_IDLE: begin
/* We will stall as soon as we are mentioned */
stall_out <= 0;
ack_out <= 0;
data_out <= 0;
/* Check for bus request condition */
if(i_cyc && i_stb) begin
stall_out <= 1;
tmp_stall <= 0;
internal_state <= STATE_FINISH;
end
end
STATE_FINISH: begin
if(i_we) begin
case (i_dat_wr_size)
1: case (i_addr[1:0])
1: mem[addr_index][15:8] <= i_dat[7:0];
2: mem[addr_index][23:16] <= i_dat[7:0];
3: mem[addr_index][31:24] <= i_dat[7:0];
default: mem[addr_index][7:0] <= i_dat[7:0];
endcase
2: case (i_addr[1])
1: mem[addr_index][31:16] <= i_dat[15:0];
default: mem[addr_index][15:0] <= i_dat[15:0];
endcase
default: mem[addr_index][31:0] <= i_dat[31:0];
endcase
end
else begin
data_out <= mem[addr_index];
end
if(i_cyc && !i_stb) begin
stall_out <= 0;
ack_out <= 1;
tmp_stall <= 1;
internal_state <= STATE_IDLE;
end
end
default: internal_state <= STATE_IDLE;
endcase
end
end
assign o_dat = data_out;
assign o_ack = ack_out;
/* the combination with | (tmp_stall & i_stb) saves one clock cycle */
assign o_stall = stall_out | (tmp_stall & i_stb);
assign addr_index[MEM_HIGH_BIT:0] = i_addr[MEM_HIGH_BIT+2:2];
endmodule