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
|
//
// Copyright 2013 Ettus Research LLC
//
module dbuf_bootram #(
parameter ADDR_WIDTH = 16,
parameter DATA_WIDTH = 32,
parameter MAX_ADDR = 16'h7FFC
) (
input clk,
input rst,
input mem_stb,
input mem_wea,
input [ADDR_WIDTH-1:0] mem_addra,
input [DATA_WIDTH-1:0] mem_dina,
output [DATA_WIDTH-1:0] mem_douta,
output reg mem_acka,
input ldr_stb,
input ldr_wea,
input [ADDR_WIDTH-1:0] ldr_addra,
input [DATA_WIDTH-1:0] ldr_dina,
output ldr_acka,
output reg zpu_rst
);
localparam SR_LDR_ADDR_REG = 4'h0;
localparam SR_LDR_DATA_REG = 4'h1;
//---------------------------------------------------------
// Mem ack logic
always @(posedge clk) begin
if (rst) mem_acka <= 0;
else mem_acka <= mem_stb & ~mem_acka;
end
//---------------------------------------------------------
// Instantiate 2 bootram modules
// They will both initialize with the pre-built ZPU firmware
//
wire ram0_ena, ram1_ena;
wire [3:0] ram0_wea, ram1_wea;
wire [12:0] ram0_addra, ram1_addra;
wire [31:0] ram0_dina, ram0_douta, ram1_dina, ram1_douta;
bootram sys_ram0(
.clka(clk),
.ena(ram0_ena),
.wea(ram0_wea),
.addra(ram0_addra),
.dina(ram0_dina),
.douta(ram0_douta));
bootram sys_ram1(
.clka(clk),
.ena(ram1_ena),
.wea(ram1_wea),
.addra(ram1_addra),
.dina(ram1_dina),
.douta(ram1_douta));
//---------------------------------------------------------
// Settings bus interface for bootloader
wire ldr_set_stb;
wire [3:0] ldr_set_addr;
wire [DATA_WIDTH-1:0] ldr_set_data;
//@TODO: This address truncation seems unclean. Maybe settings_bus can take a addr_width as a param.
wire [7:0] ldr_set_addr_w;
settings_bus #(.AWIDTH(ADDR_WIDTH), .DWIDTH(DATA_WIDTH)) ldr_settings_bus
(
.wb_clk(clk), .wb_rst(rst),
.wb_adr_i(ldr_addra), .wb_dat_i(ldr_dina),
.wb_stb_i(ldr_stb), .wb_we_i(ldr_wea), .wb_ack_o(ldr_acka),
.strobe(ldr_set_stb), .addr(ldr_set_addr_w), .data(ldr_set_data)
);
assign ldr_set_addr = ldr_set_addr_w[3:0];
//---------------------------------------------------------
// Selection logic
//
reg bootram_ptr;
reg [12:0] ldr_curr_wr_addr;
wire ldr_we_stb;
assign {ram0_ena, ram0_wea, ram0_addra, ram0_dina} = bootram_ptr ? {mem_stb, {4{(mem_wea & ~zpu_rst)}}, mem_addra[14:2], mem_dina} :
{ldr_we_stb, {4{ldr_we_stb}}, ldr_curr_wr_addr, ldr_set_data};
assign {ram1_ena, ram1_wea, ram1_addra, ram1_dina} = bootram_ptr ? {ldr_we_stb, {4{ldr_we_stb}}, ldr_curr_wr_addr, ldr_set_data} :
{mem_stb, {4{(mem_wea & ~zpu_rst)}}, mem_addra[14:2], mem_dina};
assign mem_douta = bootram_ptr ? ram0_douta : ram1_douta;
//---------------------------------------------------------
// Boot loader
//
assign ldr_we_stb = ~zpu_rst && ldr_set_stb && (ldr_set_addr == SR_LDR_DATA_REG);
always @(posedge clk) begin
if (rst) begin
zpu_rst <= 1;
bootram_ptr <= 1;
ldr_curr_wr_addr <= 13'h0;
end else if (ldr_set_stb & ~zpu_rst) begin
case (ldr_set_addr)
SR_LDR_ADDR_REG: begin
ldr_curr_wr_addr <= ldr_set_data[14:2];
end
SR_LDR_DATA_REG: begin
ldr_curr_wr_addr <= ldr_curr_wr_addr + 1;
if ({1'b0, ldr_curr_wr_addr, 2'b00} == MAX_ADDR) begin
zpu_rst <= 1;
bootram_ptr <= ~bootram_ptr;
end
end
endcase
end else begin
zpu_rst <= 0;
end
end
endmodule
|