summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2016-11-16 06:02:11 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2016-11-16 06:02:11 (GMT)
commita49171262eaf141ff039d6b92e233247732a5217 (patch)
tree08e6bff0b6e687274397360687591b8db9c08542
parenta893fbf5d707d2958ed22eac768b654473dec410 (diff)
downloadabc80-a49171262eaf141ff039d6b92e233247732a5217.zip
abc80-a49171262eaf141ff039d6b92e233247732a5217.tar.gz
abc80-a49171262eaf141ff039d6b92e233247732a5217.tar.bz2
abc80-a49171262eaf141ff039d6b92e233247732a5217.tar.xz
neopixel: compute SRAM address instead of putting it in RAM
Half the npstatram is occupied by the current pointer address, but we can compute that from conf_addr and stat_pctr. The cost turns out to be relatively minimal (approx 1 LE!) in terms of logic and saves half the RAM. This may become more important if this design is scaled to 32 bits or even higher. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--mega/npstatram.v36
-rw-r--r--neopixel.v50
2 files changed, 41 insertions, 45 deletions
diff --git a/mega/npstatram.v b/mega/npstatram.v
index e2f4a90..4b495ee 100644
--- a/mega/npstatram.v
+++ b/mega/npstatram.v
@@ -45,11 +45,11 @@ module npstatram (
q);
input clock;
- input [35:0] data;
+ input [16:0] data;
input [4:0] rdaddress;
input [4:0] wraddress;
input wren;
- output [35:0] q;
+ output [16:0] q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
@@ -59,8 +59,8 @@ module npstatram (
// synopsys translate_on
`endif
- wire [35:0] sub_wire0;
- wire [35:0] q = sub_wire0[35:0];
+ wire [16:0] sub_wire0;
+ wire [16:0] q = sub_wire0[16:0];
altsyncram altsyncram_component (
.address_a (wraddress),
@@ -80,7 +80,7 @@ module npstatram (
.clocken1 (1'b1),
.clocken2 (1'b1),
.clocken3 (1'b1),
- .data_b ({36{1'b1}}),
+ .data_b ({17{1'b1}}),
.eccstatus (),
.q_a (),
.rden_a (1'b1),
@@ -103,8 +103,8 @@ module npstatram (
altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
altsyncram_component.widthad_a = 5,
altsyncram_component.widthad_b = 5,
- altsyncram_component.width_a = 36,
- altsyncram_component.width_b = 36,
+ altsyncram_component.width_a = 17,
+ altsyncram_component.width_b = 17,
altsyncram_component.width_byteena_a = 1;
@@ -143,7 +143,7 @@ endmodule
// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0"
// Retrieval info: PRIVATE: JTAG_ID STRING "NONE"
// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0"
-// Retrieval info: PRIVATE: MEMSIZE NUMERIC "1152"
+// Retrieval info: PRIVATE: MEMSIZE NUMERIC "544"
// Retrieval info: PRIVATE: MEM_IN_BITS NUMERIC "0"
// Retrieval info: PRIVATE: MIFfilename STRING ""
// Retrieval info: PRIVATE: OPERATION_MODE NUMERIC "2"
@@ -163,10 +163,10 @@ endmodule
// Retrieval info: PRIVATE: USE_DIFF_CLKEN NUMERIC "0"
// Retrieval info: PRIVATE: UseDPRAM NUMERIC "1"
// Retrieval info: PRIVATE: VarWidth NUMERIC "0"
-// Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "36"
-// Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "36"
-// Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "36"
-// Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "36"
+// Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "17"
+// Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "17"
+// Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "17"
+// Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "17"
// Retrieval info: PRIVATE: WRADDR_ACLR_B NUMERIC "0"
// Retrieval info: PRIVATE: WRADDR_REG_B NUMERIC "0"
// Retrieval info: PRIVATE: WRCTRL_ACLR_B NUMERIC "0"
@@ -189,21 +189,21 @@ endmodule
// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_MIXED_PORTS STRING "DONT_CARE"
// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "5"
// Retrieval info: CONSTANT: WIDTHAD_B NUMERIC "5"
-// Retrieval info: CONSTANT: WIDTH_A NUMERIC "36"
-// Retrieval info: CONSTANT: WIDTH_B NUMERIC "36"
+// Retrieval info: CONSTANT: WIDTH_A NUMERIC "17"
+// Retrieval info: CONSTANT: WIDTH_B NUMERIC "17"
// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1"
// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock"
-// Retrieval info: USED_PORT: data 0 0 36 0 INPUT NODEFVAL "data[35..0]"
-// Retrieval info: USED_PORT: q 0 0 36 0 OUTPUT NODEFVAL "q[35..0]"
+// Retrieval info: USED_PORT: data 0 0 17 0 INPUT NODEFVAL "data[16..0]"
+// Retrieval info: USED_PORT: q 0 0 17 0 OUTPUT NODEFVAL "q[16..0]"
// Retrieval info: USED_PORT: rdaddress 0 0 5 0 INPUT NODEFVAL "rdaddress[4..0]"
// Retrieval info: USED_PORT: wraddress 0 0 5 0 INPUT NODEFVAL "wraddress[4..0]"
// Retrieval info: USED_PORT: wren 0 0 0 0 INPUT GND "wren"
// Retrieval info: CONNECT: @address_a 0 0 5 0 wraddress 0 0 5 0
// Retrieval info: CONNECT: @address_b 0 0 5 0 rdaddress 0 0 5 0
// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0
-// Retrieval info: CONNECT: @data_a 0 0 36 0 data 0 0 36 0
+// Retrieval info: CONNECT: @data_a 0 0 17 0 data 0 0 17 0
// Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0
-// Retrieval info: CONNECT: q 0 0 36 0 @q_b 0 0 36 0
+// Retrieval info: CONNECT: q 0 0 17 0 @q_b 0 0 17 0
// Retrieval info: GEN_FILE: TYPE_NORMAL npstatram.v TRUE
// Retrieval info: GEN_FILE: TYPE_NORMAL npstatram.inc FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL npstatram.cmp FALSE
diff --git a/neopixel.v b/neopixel.v
index a0ac49b..9de6f77 100644
--- a/neopixel.v
+++ b/neopixel.v
@@ -104,8 +104,8 @@ module neopixel (
assign cpu_di = ~cpu_rd_n ? conf_cpu_q : ~8'b0;
- wire [35:0] b_stat_q;
- reg [35:0] b_stat_d;
+ wire [16:0] b_stat_q;
+ reg [16:0] b_stat_d;
// Status RAM
npstatram npstatram (
@@ -125,52 +125,48 @@ module neopixel (
wire [7:0] b_conf_plen = b_conf_q[23:16]; // Pattern len
wire [7:0] b_conf_clen = b_conf_q[31:24]; // Chain len
- wire [15:0] b_stat_addr = b_stat_q[15:0];
- wire [7:0] b_stat_pctr = b_stat_q[23:16];
- wire [8:0] b_stat_cctr = b_stat_q[32:24];
+ wire [7:0] b_stat_pctr = b_stat_q[7:0];
+ wire [8:0] b_stat_cctr = b_stat_q[16:8];
// Channel is enabled if plen > 0 or global disable
- wire b_ena = |b_conf_plen & g_enable;
+ wire b_ena = |b_conf_plen & |b_conf_clen & g_enable;
// True before stat ctr wrap. Cycles -1 and -2 are for reset
wire b_stat_end = b_stat_cctr[8] & ~b_stat_cctr[0];
+ wire [7:0] b_stat_pctr_p1 = b_stat_pctr + 1'b1;
+
always @(*)
begin
- b_stat_d[35:33] = 3'bxxx;
- b_stat_d[32:0] = b_stat_q[32:0];
+ b_stat_d = b_stat_q;
if ( ~b_ena )
begin
- b_stat_d[15:0] = b_conf_addr;
- b_stat_d[32:24] = ~9'b0;
+ b_stat_d[7:0] = 8'b0;
+ b_stat_d[16:8] = ~9'b0;
end
else
begin
- if (&b_ctr[7:5]) // New byte?
+ if (b_ctr[9] & &b_ctr[7:5]) // New word?
begin
- b_stat_d[15:0] = b_stat_addr + 1'b1;
-
- if ( b_ctr[9] ) // New word?
- begin
- if ( b_stat_end | ~|b_stat_pctr )
- b_stat_d[15:0] = b_conf_addr;
-
- b_stat_d[23:16] =
- (( b_stat_end | ~|b_stat_pctr ) ?
- b_conf_plen : b_stat_pctr) - 1'b1;
-
- b_stat_d[32:24] =
- (b_stat_end ?
- {1'b0, b_conf_clen} : b_stat_cctr) - 1'b1;
- end // if ( b_ctr[9] )
- end // if ( &b_ctr[7:5] )
+ b_stat_d[7:0] = (b_stat_end | ~|(b_stat_pctr_p1^b_conf_plen))
+ ? 8'b0 : b_stat_pctr_p1;
+
+ b_stat_d[16:8] = (b_stat_end
+ ? {1'b0, b_conf_clen} : b_stat_cctr) - 1'b1;
+ end
end // else: !if( ~b_ena )
end // always @ (*)
// Output: are we in chain reset?
wire b_in_rst = ~b_ena | b_stat_cctr[8];
+ // Byte address in RAM
+ // The WS2812 wants data in order GRB, so we swizzle the addresses
+ // slightly so we can use RGB order in memory.
+ wire [1:0] b_ctr_byte = { b_ctr[9], ~b_ctr[9]^b_ctr[8] };
+ wire [15:0] b_stat_addr = b_conf_addr + b_stat_pctr*2'd3 + b_ctr_byte;
+
// b_ctr[7:5] is inverted as bit order is bigendian
assign ram_a = { b_stat_addr, ~b_ctr[7:5] };