如何在 IceStorm 的 512x8 读取模式下使用 iCE40 4K 块 RAM?
How can I use iCE40 4K block RAM in 512x8 read mode with IceStorm?
我想知道如何使用我的 iCE40HX-8K 分线板上的块 RAM。我想以 512x8 配置访问它,据我从文档中可以看出项目 IceStorm 支持它,但我无法让它像我预期的那样工作。
如果我理解正确,初始化 SB_RAM40_4K 原语并将 READ_MODE 参数设置为 1 应该将块设置为 512x8 读取模式,该模式使用 9 位读取地址,并读取 8每个地址的数据位。
这是我能想到的最简单的例子。它设置了一个 SB_RAM40_4K 和一些预初始化的内存,并直接读取板载 LED 的引脚。
hx8kboard.pcf
set_io leds[0] B5
set_io leds[1] B4
set_io leds[2] A2
set_io leds[3] A1
set_io leds[4] C5
set_io leds[5] C4
set_io leds[6] B3
set_io leds[7] C3
set_io clk J3
top.v
module top (
output [7:0] leds,
input clk
);
//reg [8:0] raddr = 8'd0;
reg [8:0] raddr = 8'd1;
SB_RAM40_4K #(
.INIT_0(256'h00000000000000000000000000000000000000000000000000000000_44_33_22_11),
.WRITE_MODE(1),
.READ_MODE(1)
) ram40_4k_512x8 (
.RDATA(leds),
.RADDR(raddr),
.RCLK(clk),
.RCLKE(1'b1),
.RE(1'b1),
.WADDR(8'b0),
.WCLK(1'b0),
.WCLKE(1'b0),
.WDATA(8'b0),
.WE(1'b0)
);
endmodule
raddr == 0 时的 LED 输出
\|/ \|/
O O O O O O O O
raddr == 1 时的 LED 输出
\|/ \|/ \|/ \|/
O O O O O O O O
我认为 512x8 模式下的地址 1 应该是 RAM 的第二个 8 位,即 8'h22
或 8'b0010010
。相反,我得到 8'h33
或 8'b00110011
。经过一些实验,这似乎是 16 位读取的低 8 位。
我不确定哪里出错了。任何帮助理解这里发生的事情的帮助将不胜感激。谢谢!
这个问题实际上与 Yosys 或 Project IceStorm 无关。 IceStorm 流程和 Lattice iCEcube2 流程的 SB_RAM40_4K
INIT_*
参数使用的格式相同。然而,莱迪思在记录这种格式方面做得非常非常糟糕。否则,我只会将您指向正确的 Lattice 文档。:)
您对 512x8 模式感兴趣。首先,您需要知道在 512x8 模式下,仅使用 .RDATA()
和 .WDATA()
的偶数位(而不是 8 LSB 位,如您的代码所建议的那样!)。
.INIT_*
中的数据存储为每个参数的 16 个 16 位字。 .INIT_0()
中的最低 16 位字包含地址 0 的 8 位字的偶数位和地址 256 的 8 位字的奇数位。
.INIT_0()
中的下一个 16 位字包含字 1 和 257。.INIT_1()
中的最低 16 位包含字 16 和 272,依此类推。
研究这类东西的最简单方法可能是阅读 /usr/local/share/yosys/ice40/cells_sim.v
中的 SB_RAM40_4K
仿真模型,或者让 Yosys 推断内存并观察 yosys 做了什么。例如下面的设计:
module test(input clk, wen, input [8:0] addr, input [7:0] wdata, output reg [7:0] rdata);
reg [7:0] mem [0:511];
initial mem[0] = 255;
always @(posedge clk) begin
if (wen) mem[addr] <= wdata;
rdata <= mem[addr];
end
endmodule
当运行到yosys -p 'synth_ice40; write_verilog' test.v
时将产生以下输出:
(* top = 1 *)
(* src = "test.v:1" *)
module test(clk, wen, addr, wdata, rdata);
(* src = "/usr/local/bin/../share/yosys/ice40/brams_map.v:255" *)
(* unused_bits = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15" *)
wire [15:0] _0_;
(* src = "test.v:1" *)
input [8:0] addr;
(* src = "test.v:1" *)
input clk;
(* src = "test.v:1" *)
output [7:0] rdata;
(* src = "test.v:1" *)
input [7:0] wdata;
(* src = "test.v:1" *)
input wen;
(* src = "/usr/local/bin/../share/yosys/ice40/brams_map.v:277|/usr/local/bin/../share/yosys/ice40/brams_map.v:35" *)
SB_RAM40_4K #(
.INIT_0(256'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1x1x1x1x1x1x1x1),
.INIT_1(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_2(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_3(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_4(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_5(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_6(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_7(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_8(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_9(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_A(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_B(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_C(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_D(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_E(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_F(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.READ_MODE(32'sd1),
.WRITE_MODE(32'sd1)
) \mem.0.0.0 (
.MASK(16'hxxxx),
.RADDR({ 2'h0, addr }),
.RCLK(clk),
.RCLKE(1'h1),
.RDATA({ _0_[15], rdata[7], _0_[13], rdata[6], _0_[11], rdata[5], _0_[9], rdata[4], _0_[7], rdata[3], _0_[5], rdata[2], _0_[3], rdata[1], _0_[1], rdata[0] }),
.RE(1'h1),
.WADDR({ 2'h0, addr }),
.WCLK(clk),
.WCLKE(wen),
.WDATA({ 1'hx, wdata[7], 1'hx, wdata[6], 1'hx, wdata[5], 1'hx, wdata[4], 1'hx, wdata[3], 1'hx, wdata[2], 1'hx, wdata[1], 1'hx, wdata[0] }),
.WE(1'h1)
);
endmodule
(一直向右滚动以查看为 mem[0] = 255
初始化生成的初始化模式。)
我想知道如何使用我的 iCE40HX-8K 分线板上的块 RAM。我想以 512x8 配置访问它,据我从文档中可以看出项目 IceStorm 支持它,但我无法让它像我预期的那样工作。
如果我理解正确,初始化 SB_RAM40_4K 原语并将 READ_MODE 参数设置为 1 应该将块设置为 512x8 读取模式,该模式使用 9 位读取地址,并读取 8每个地址的数据位。
这是我能想到的最简单的例子。它设置了一个 SB_RAM40_4K 和一些预初始化的内存,并直接读取板载 LED 的引脚。
hx8kboard.pcf
set_io leds[0] B5
set_io leds[1] B4
set_io leds[2] A2
set_io leds[3] A1
set_io leds[4] C5
set_io leds[5] C4
set_io leds[6] B3
set_io leds[7] C3
set_io clk J3
top.v
module top (
output [7:0] leds,
input clk
);
//reg [8:0] raddr = 8'd0;
reg [8:0] raddr = 8'd1;
SB_RAM40_4K #(
.INIT_0(256'h00000000000000000000000000000000000000000000000000000000_44_33_22_11),
.WRITE_MODE(1),
.READ_MODE(1)
) ram40_4k_512x8 (
.RDATA(leds),
.RADDR(raddr),
.RCLK(clk),
.RCLKE(1'b1),
.RE(1'b1),
.WADDR(8'b0),
.WCLK(1'b0),
.WCLKE(1'b0),
.WDATA(8'b0),
.WE(1'b0)
);
endmodule
raddr == 0 时的 LED 输出
\|/ \|/
O O O O O O O O
raddr == 1 时的 LED 输出
\|/ \|/ \|/ \|/
O O O O O O O O
我认为 512x8 模式下的地址 1 应该是 RAM 的第二个 8 位,即 8'h22
或 8'b0010010
。相反,我得到 8'h33
或 8'b00110011
。经过一些实验,这似乎是 16 位读取的低 8 位。
我不确定哪里出错了。任何帮助理解这里发生的事情的帮助将不胜感激。谢谢!
这个问题实际上与 Yosys 或 Project IceStorm 无关。 IceStorm 流程和 Lattice iCEcube2 流程的 SB_RAM40_4K
INIT_*
参数使用的格式相同。然而,莱迪思在记录这种格式方面做得非常非常糟糕。否则,我只会将您指向正确的 Lattice 文档。:)
您对 512x8 模式感兴趣。首先,您需要知道在 512x8 模式下,仅使用 .RDATA()
和 .WDATA()
的偶数位(而不是 8 LSB 位,如您的代码所建议的那样!)。
.INIT_*
中的数据存储为每个参数的 16 个 16 位字。 .INIT_0()
中的最低 16 位字包含地址 0 的 8 位字的偶数位和地址 256 的 8 位字的奇数位。
.INIT_0()
中的下一个 16 位字包含字 1 和 257。.INIT_1()
中的最低 16 位包含字 16 和 272,依此类推。
研究这类东西的最简单方法可能是阅读 /usr/local/share/yosys/ice40/cells_sim.v
中的 SB_RAM40_4K
仿真模型,或者让 Yosys 推断内存并观察 yosys 做了什么。例如下面的设计:
module test(input clk, wen, input [8:0] addr, input [7:0] wdata, output reg [7:0] rdata);
reg [7:0] mem [0:511];
initial mem[0] = 255;
always @(posedge clk) begin
if (wen) mem[addr] <= wdata;
rdata <= mem[addr];
end
endmodule
当运行到yosys -p 'synth_ice40; write_verilog' test.v
时将产生以下输出:
(* top = 1 *)
(* src = "test.v:1" *)
module test(clk, wen, addr, wdata, rdata);
(* src = "/usr/local/bin/../share/yosys/ice40/brams_map.v:255" *)
(* unused_bits = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15" *)
wire [15:0] _0_;
(* src = "test.v:1" *)
input [8:0] addr;
(* src = "test.v:1" *)
input clk;
(* src = "test.v:1" *)
output [7:0] rdata;
(* src = "test.v:1" *)
input [7:0] wdata;
(* src = "test.v:1" *)
input wen;
(* src = "/usr/local/bin/../share/yosys/ice40/brams_map.v:277|/usr/local/bin/../share/yosys/ice40/brams_map.v:35" *)
SB_RAM40_4K #(
.INIT_0(256'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1x1x1x1x1x1x1x1),
.INIT_1(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_2(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_3(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_4(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_5(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_6(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_7(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_8(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_9(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_A(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_B(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_C(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_D(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_E(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.INIT_F(256'hxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),
.READ_MODE(32'sd1),
.WRITE_MODE(32'sd1)
) \mem.0.0.0 (
.MASK(16'hxxxx),
.RADDR({ 2'h0, addr }),
.RCLK(clk),
.RCLKE(1'h1),
.RDATA({ _0_[15], rdata[7], _0_[13], rdata[6], _0_[11], rdata[5], _0_[9], rdata[4], _0_[7], rdata[3], _0_[5], rdata[2], _0_[3], rdata[1], _0_[1], rdata[0] }),
.RE(1'h1),
.WADDR({ 2'h0, addr }),
.WCLK(clk),
.WCLKE(wen),
.WDATA({ 1'hx, wdata[7], 1'hx, wdata[6], 1'hx, wdata[5], 1'hx, wdata[4], 1'hx, wdata[3], 1'hx, wdata[2], 1'hx, wdata[1], 1'hx, wdata[0] }),
.WE(1'h1)
);
endmodule
(一直向右滚动以查看为 mem[0] = 255
初始化生成的初始化模式。)