summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2016-11-15 08:14:40 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2016-11-15 08:14:40 (GMT)
commitc82eafb59f3f18021b29d145d5ddc4fa88442cf0 (patch)
treed4bf84892674a7ee7fc64e2c41a5f167b75b0af7
parentd22699e168ef2dd6b79c19c0a08b51130db2385e (diff)
downloadabc80-c82eafb59f3f18021b29d145d5ddc4fa88442cf0.zip
abc80-c82eafb59f3f18021b29d145d5ddc4fa88442cf0.tar.gz
abc80-c82eafb59f3f18021b29d145d5ddc4fa88442cf0.tar.bz2
abc80-c82eafb59f3f18021b29d145d5ddc4fa88442cf0.tar.xz
neopixel: now works for the first pixel...
However, we seem to fail on subseqent ones...
-rw-r--r--abc80.qsf62
-rw-r--r--abc80.v207
-rw-r--r--neopixel.v236
-rw-r--r--npgpio.odsbin0 -> 15947 bytes
-rw-r--r--ports.txt8
5 files changed, 439 insertions, 74 deletions
diff --git a/abc80.qsf b/abc80.qsf
index 5507830..2ce9640 100644
--- a/abc80.qsf
+++ b/abc80.qsf
@@ -433,7 +433,7 @@ set_global_assignment -name GENERATE_JAM_FILE ON
# SignalTap II Assignments
# ========================
-set_global_assignment -name ENABLE_SIGNALTAP OFF
+set_global_assignment -name ENABLE_SIGNALTAP ON
# LogicLock Region Assignments
# ============================
@@ -536,11 +536,11 @@ set_global_assignment -name FMAX_REQUIREMENT "24 MHz" -section_id clock_24
set_instance_assignment -name CLOCK_SETTINGS clock_24 -to clock_24[0]
set_instance_assignment -name CLOCK_SETTINGS clock_24 -to clock_24[1]
-set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
+set_global_assignment -name PARTITION_NETLIST_TYPE POST_FIT -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
-set_global_assignment -name USE_SIGNALTAP_FILE stp2.stp
+set_global_assignment -name USE_SIGNALTAP_FILE stp1.stp
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "NO HEAT SINK WITH STILL AIR"
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON
@@ -575,7 +575,15 @@ set_global_assignment -name AUTO_DELAY_CHAINS_FOR_HIGH_FANOUT_INPUT_PINS ON
set_global_assignment -name TIMEQUEST_DO_REPORT_TIMING ON
set_global_assignment -name EDA_OUTPUT_DATA_FORMAT "VERILOG HDL" -section_id eda_simulation
-set_global_assignment -name SLD_FILE "/home/hpa/abc80/abc80-de1/stp2_auto_stripped.stp"
+set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:data/revrom.tcl"
+
+set_global_assignment -name OPTIMIZE_IOC_REGISTER_PLACEMENT_FOR_TIMING "PACK ALL IO REGISTERS"
+set_global_assignment -name FINAL_PLACEMENT_OPTIMIZATION ALWAYS
+set_global_assignment -name AUTO_PACKED_REGISTERS_STRATIXII "SPARSE AUTO"
+set_global_assignment -name RTLV_GROUP_RELATED_NODES_TMV ON
+set_global_assignment -name VERILOG_FILE mega/npstatram.v
+set_global_assignment -name VERILOG_FILE mega/npconfram.v
+set_global_assignment -name VERILOG_FILE neopixel.v
set_global_assignment -name VERILOG_FILE mega/revrom.v
set_global_assignment -name VERILOG_FILE mega/fgfifo.v
set_global_assignment -name VERILOG_FILE sync.v
@@ -619,10 +627,44 @@ set_global_assignment -name VERILOG_FILE abc80.v
set_global_assignment -name SDC_FILE abc80.sdc
set_global_assignment -name SOURCE_FILE db/abc80.cmp.rdb
set_global_assignment -name SIGNALTAP_FILE stp2.stp
-set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:data/revrom.tcl"
-
-set_global_assignment -name OPTIMIZE_IOC_REGISTER_PLACEMENT_FOR_TIMING "PACK ALL IO REGISTERS"
-set_global_assignment -name FINAL_PLACEMENT_OPTIMIZATION ALWAYS
-set_global_assignment -name AUTO_PACKED_REGISTERS_STRATIXII "SPARSE AUTO"
-set_global_assignment -name RTLV_GROUP_RELATED_NODES_TMV ON
+set_global_assignment -name SIGNALTAP_FILE stp1.stp
+set_global_assignment -name SLD_NODE_CREATOR_ID 110 -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_ENTITY_NAME sld_signaltap -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_clk -to "pll1:pll1|altpll:altpll_component|_clk2" -section_id auto_signaltap_0
+set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[0] -to npled_do -section_id auto_signaltap_0
+set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[0] -to npled_do -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_INFO=805334528" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_POWER_UP_TRIGGER=0" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STORAGE_QUALIFIER_INVERSION_MASK_LENGTH=0" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ATTRIBUTE_MEM_MODE=OFF" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STATE_FLOW_USE_GENERATED=0" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STATE_BITS=11" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_BUFFER_FULL_STOP=1" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_CURRENT_RESOURCE_WIDTH=1" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_LEVEL=1" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_IN_ENABLED=0" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ADVANCED_TRIGGER_ENTITY=basic,1," -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_LEVEL_PIPELINE=1" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ENABLE_ADVANCED_TRIGGER=0" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_SEGMENT_SIZE=4096" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_SAMPLE_DEPTH=4096" -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[1] -to gpio_io[2] -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[2] -to "neopixel:neopixel|e_data[0]" -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[3] -to "neopixel:neopixel|e_in_rst[0]" -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[4] -to "neopixel:neopixel|pulse[0]" -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[5] -to "neopixel:neopixel|pulse[1]" -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[6] -to np_enable -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[1] -to gpio_io[2] -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[2] -to "neopixel:neopixel|e_data[0]" -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[3] -to "neopixel:neopixel|e_in_rst[0]" -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[4] -to "neopixel:neopixel|pulse[0]" -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[5] -to "neopixel:neopixel|pulse[1]" -section_id auto_signaltap_0
+set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[6] -to np_enable -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_DATA_BITS=7" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_BITS=7" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_INVERSION_MASK=00000000000000000000000000000000000000000000000" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_INVERSION_MASK_LENGTH=47" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_LOWORD=8651" -section_id auto_signaltap_0
+set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_HIWORD=56101" -section_id auto_signaltap_0
+set_global_assignment -name SLD_FILE "/home/hpa/abc80/abc80-de1/stp1_auto_stripped.stp"
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file
diff --git a/abc80.v b/abc80.v
index 324f118..702c1ee 100644
--- a/abc80.v
+++ b/abc80.v
@@ -19,6 +19,8 @@
// the Lancelot add-on board from www.fpga.nl
//
+`define IN_IO_PAD (* altera_attribute="-name FAST_OUTPUT_REGISTER ON; -name FAST_OUTPUT_ENABLE_REGISTER ON; -name FAST_INPUT_REGISTER ON" *)
+
module abc80 (
input clock_50, // 50 MHz clock
input [1:0] clock_24, // 24 MHz clock (on two pins)
@@ -61,8 +63,7 @@ module abc80 (
output sram_we_n, // SRAM WE#
output [1:0] sram_be_n, // SRAM LB#, UB#
output [17:0] sram_a, // SRAM address bus
- (* altera_attribute="-name FAST_OUTPUT_REGISTER ON; -name FAST_OUTPUT_ENABLE_REGISTER ON; -name FAST_INPUT_REGISTER ON" *)
- inout [15:0] sram_dq, // SRAM data bus
+`IN_IO_PAD inout [15:0] sram_dq, // SRAM data bus
output sd_clk, // SD card clock
inout sd_cmd, // SD card DI/MOSI/CMD
@@ -88,7 +89,7 @@ module abc80 (
inout i2c_scl, // I2C SCK line
inout i2c_sda, // I2C SDA line
- inout [35:0] gpio_0, // GPIO headers
+`IN_IO_PAD inout [35:0] gpio_0, // GPIO headers
inout [35:0] gpio_1 // GPIO headers
);
@@ -503,10 +504,10 @@ module abc80 (
reg sram_oe_q;
reg sram_we_q;
reg sram_fgrd;
- reg [18:0] sram_addr_q;
+ reg [17:0] sram_addr_q;
reg [1:0] sram_be_q;
reg [15:0] sram_d_q; // Output data (from write)
- reg [15:0] sram_d_en;
+ reg sram_d_en; // Data out enable
reg [15:0] sram_q; // Latched input data (in I/O pad)
reg sram_mux_ctl; // addr[0] with a delay
@@ -521,8 +522,13 @@ module abc80 (
// msel[] to save two sram_clk cycles.
wire sram_cpu = msel_q[0] & ~cpu_mreq_n & cpu_clk_en_q;
- wire [18:0] npled_addr = 19'bx; // Just bullshit for now
- reg [7:0] npled_do;
+ // This is a *bit* address
+ wire [21:0] npled_addr;
+ reg npled_do;
+ reg [3:0] npled_addr_q; // Bit inside SRAM word, one cpu_clk delayed
+
+ always @(posedge cpu_clk)
+ npled_addr_q <= npled_addr[3:0];
always @(negedge rst_n or posedge sram_clk)
if ( ~rst_n )
@@ -530,23 +536,21 @@ module abc80 (
sram_ce_q <= 1'b0;
sram_oe_q <= 1'b0;
sram_we_q <= 1'b0;
- sram_d_en <= ~16'b0;
+ sram_d_en <= 1'b1;
sram_fg_q <= 1'b0;
sram_cpu_q <= 1'b0;
- sram_addr_q <= 19'bx;
+ sram_addr_q <= 18'bx;
+ sram_mux_ctl <= 1'bx;
sram_be_q <= 2'b00;
sram_d_q <= 16'bx;
sram_q <= 16'bx;
sram_do_q <= 8'bx;
sram_fgdata_q <= 8'bx;
- npled_do <= 8'bx;
+ npled_do <= 1'bx;
end // if ( ~rst_n )
else
begin
case (sram_clk_phase)
- 3'd0:
- sram_mux_ctl <= sram_addr_q[0];
-
3'd1:
begin
sram_q <= sram_dq;
@@ -554,43 +558,45 @@ module abc80 (
if (sram_cpu)
begin
- sram_ce_q <= 1'b1;
- sram_we_q <= ~cpu_wr_n & ~mmu_ro;
- sram_oe_q <= ~cpu_rd_n;
- sram_d_en <= {16{cpu_rd_n}};
- sram_addr_q <= mmu_a[18:0];
- sram_be_q <= {mmu_a[0], ~mmu_a[0]};
- sram_cpu_q <= 1'b1;
- sram_fg_q <= 1'b0;
+ sram_ce_q <= 1'b1;
+ sram_we_q <= ~cpu_wr_n & ~mmu_ro;
+ sram_oe_q <= ~cpu_rd_n;
+ sram_d_en <= cpu_rd_n;
+ sram_addr_q <= mmu_a[18:1];
+ sram_be_q <= {mmu_a[0], ~mmu_a[0]};
+ sram_mux_ctl <= mmu_a[0];
+ sram_cpu_q <= 1'b1;
+ sram_fg_q <= 1'b0;
end
else if (sram_fgrd)
begin
- sram_ce_q <= 1'b1;
- sram_we_q <= 1'b0;
- sram_oe_q <= 1'b1;
- sram_d_en <= 16'b0;
- sram_addr_q <= sram_fgaddr;
- sram_be_q <= {sram_fgaddr[0], ~sram_fgaddr[0]};
- sram_cpu_q <= 1'b0;
- sram_fg_q <= 1'b1;
+ sram_ce_q <= 1'b1;
+ sram_we_q <= 1'b0;
+ sram_oe_q <= 1'b1;
+ sram_d_en <= 1'b0;
+ sram_addr_q <= sram_fgaddr[18:1];
+ sram_mux_ctl <= sram_fgaddr[0];
+ sram_be_q <= 2'b11;
+ sram_cpu_q <= 1'b0;
+ sram_fg_q <= 1'b1;
end
else
begin
- sram_ce_q <= 1'b0;
- sram_we_q <= 1'b0;
- sram_oe_q <= 1'b0;
- sram_d_en <= ~16'b0; // Don't float the bus
- sram_addr_q <= 19'bx;
- sram_be_q <= 2'b00;
- sram_cpu_q <= 1'b0;
- sram_fg_q <= 1'b0;
+ sram_ce_q <= 1'b0;
+ sram_we_q <= 1'b0;
+ sram_oe_q <= 1'b0;
+ sram_d_en <= 1'b1; // Don't float the bus
+ sram_addr_q <= 18'bx;
+ sram_mux_ctl <= 1'bx;
+ sram_be_q <= 2'b00;
+ sram_cpu_q <= 1'b0;
+ sram_fg_q <= 1'b0;
end // else: !if(sram_fgrd)
end
3'd2:
begin
- npled_do <= sram_mux_out;
- sram_mux_ctl <= sram_addr_q[0];
+ npled_do <= sram_q[npled_addr_q[3:0]];
end
3'd4:
@@ -602,13 +608,13 @@ module abc80 (
begin
sram_q <= sram_dq;
- sram_ce_q <= 1'b0;
+ sram_ce_q <= 1'b1;
sram_we_q <= 1'b0;
- sram_oe_q <= 1'b0;
- sram_be_q <= 2'b00;
- sram_d_en <= ~16'b0; // Don't float the bus
- sram_d_q <= cpu_do; // For better I/O packing
- sram_addr_q <= npled_addr;
+ sram_oe_q <= 1'b1;
+ sram_be_q <= 2'b11;
+ sram_d_en <= 1'b0;
+ sram_d_q <= { cpu_do, cpu_do }; // For better I/O packing
+ sram_addr_q <= npled_addr[21:4];
end
3'd6:
@@ -634,20 +640,14 @@ module abc80 (
// Driving output pins.
- assign sram_a = sram_addr_q;
+ assign sram_a = sram_addr_q;
assign sram_be_n = ~sram_be_q;
assign sram_ce_n = ~sram_ce_q;
assign sram_oe_n = ~sram_oe_q;
assign sram_we_n = ~sram_we_q;
- genvar i;
- generate
- for (i = 0; i < 16; i=i+1)
- begin: gen_sram_dq
- assign sram_dq[i] = sram_d_en[i] ? sram_d_q[i] : 1'bz;
- end
- endgenerate
+ assign sram_dq = sram_d_en ? sram_d_q : 16'bz;
always @(negedge rst_n or posedge cpu_clk)
if ( ~rst_n )
@@ -1176,25 +1176,95 @@ module abc80 (
// ------------------------------------------------------------------------
+ // Neopixel controller
+ // ------------------------------------------------------------------------
+ reg np_enable;
+ reg [6:0] np_cpu_addr;
+ wire [7:0] np_cpu_di;
+ wire [31:0] npled_out;
+
+ assign npled_addr[21:19] = 3'b000;
+
+ neopixel neopixel (
+ .rst_n (rst_n),
+ .clk (cpu_clk),
+ .enable (np_enable),
+
+ .cpu_do (cpu_do),
+ .cpu_a (np_cpu_addr),
+ .cpu_wr_n (~(intio_sel & ~cpu_wr_n &
+ (cpu_a[6:0] == 7'h1d))),
+ .cpu_rd_n (1'b0), // Multiplex handled elsewhere
+ .cpu_di (np_cpu_di),
+ .ram_a (npled_addr[18:0]),
+ .ram_q (npled_do),
+ .npout (npled_out)
+ );
+
+ // ------------------------------------------------------------------------
// GPIO(0) header
- //
- // gpio_io: the actual state of the pins
- // gpio_dat: data for output pin
- // gpio_ctl: 0 for input/tristate, 1 for output
// ------------------------------------------------------------------------
- reg [35:0] gpio_io;
- reg [35:0] gpio_dat;
- reg [35:0] gpio_ctl;
+ reg [35:0] gpio_io; // Data read from pin
+ reg [35:0] gpio_ctl; // GPIO control word from CPU
+ reg [35:0] gpio_dat; // GPIO data word from CPU
+ wire [35:0] gpio_npled; // Mapping from npled channels to GPIOs
+
+ reg [35:0] gpio_din; // Data in register on pad
+ reg [35:0] gpio_ena; // Output enable register on pad
+
+ always @(posedge fast_clk)
+ gpio_io <= gpio_0; // Read data from pad
+
+ // npled channels to GPIO mappings, when npleds are enabled
+ assign gpio_npled[ 0] = npled_out[ 4];
+ assign gpio_npled[ 1] = 1'b0; // OE3#
+ assign gpio_npled[ 2] = npled_out[ 0];
+ assign gpio_npled[ 3] = npled_out[31];
+ assign gpio_npled[ 4] = npled_out[ 1];
+ assign gpio_npled[ 5] = npled_out[30];
+ assign gpio_npled[ 6] = npled_out[ 2];
+ assign gpio_npled[ 7] = npled_out[29];
+ assign gpio_npled[ 8] = npled_out[ 3];
+ assign gpio_npled[ 9] = npled_out[28];
+ assign gpio_npled[10] = npled_out[ 5];
+ assign gpio_npled[11] = npled_out[26];
+ assign gpio_npled[12] = npled_out[ 6];
+ assign gpio_npled[13] = npled_out[25];
+ assign gpio_npled[14] = npled_out[ 7];
+ assign gpio_npled[15] = npled_out[24];
+ assign gpio_npled[16] = 1'b0; // OE0#
+ assign gpio_npled[17] = npled_out[27];
+ assign gpio_npled[18] = npled_out[11];
+ assign gpio_npled[19] = 1'b0; // OE2#
+ assign gpio_npled[20] = npled_out[ 8];
+ assign gpio_npled[21] = npled_out[23];
+ assign gpio_npled[22] = npled_out[ 9];
+ assign gpio_npled[23] = npled_out[22];
+ assign gpio_npled[24] = npled_out[10];
+ assign gpio_npled[25] = npled_out[21];
+ assign gpio_npled[26] = npled_out[12];
+ assign gpio_npled[27] = npled_out[19];
+ assign gpio_npled[28] = npled_out[13];
+ assign gpio_npled[29] = npled_out[18];
+ assign gpio_npled[30] = npled_out[14];
+ assign gpio_npled[31] = npled_out[17];
+ assign gpio_npled[32] = npled_out[15];
+ assign gpio_npled[33] = npled_out[16];
+ assign gpio_npled[34] = 1'b0; // OE1#
+ assign gpio_npled[35] = npled_out[20];
always @(posedge fast_clk)
- gpio_io <= gpio_0;
+ gpio_din <= np_enable ? gpio_npled : gpio_dat;
+ always @(posedge fast_clk)
+ gpio_ena <= gpio_ctl | {36{np_enable}};
+
genvar pin;
generate
for (pin = 0; pin < 36; pin = pin + 1)
begin: gpio0_assign
- assign gpio_0[pin] = gpio_ctl[pin] ? gpio_dat[pin] : 1'bz;
+ assign gpio_0[pin] = gpio_ena[pin] ? gpio_din[pin] : 1'bz;
end
endgenerate
@@ -1243,6 +1313,9 @@ module abc80 (
intio_do <= ~8'b0;
+ np_enable <= 1'b0;
+ np_cpu_addr <= 7'b0;
+
fgctl <= 8'h00;
fgpage <= 5'h05; // After BASIC80 in RAM
@@ -1301,6 +1374,12 @@ module abc80 (
prog_s7[2] <= cpu_do[6:0];
7'b0011011:
prog_s7[3] <= cpu_do[6:0];
+ 7'b0011100:
+ begin
+ np_enable <= cpu_do[7];
+ np_cpu_addr <= cpu_do[6:0];
+ end
+ // 7'b0011101: np data write, decoded elsewhere
7'b0011110:
fgctl <= cpu_do[7:0];
7'b0011111:
@@ -1373,6 +1452,10 @@ module abc80 (
intio_do <= { 1'b0, prog_s7[2] };
7'b0011011:
intio_do <= { 1'b0, prog_s7[3] };
+ 7'b0011100:
+ intio_do <= { np_enable, np_cpu_addr[6:0] };
+ 7'b0011101:
+ intio_do <= np_cpu_di;
7'b0011110:
intio_do <= fgctl;
7'b0011111:
diff --git a/neopixel.v b/neopixel.v
new file mode 100644
index 0000000..28ebc2c
--- /dev/null
+++ b/neopixel.v
@@ -0,0 +1,236 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2016 H. Peter Anvin - All Rights Reserved
+//
+// This program 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, Inc., 51 Franklin St, Fifth Floor,
+// Boston MA 02110-1301, USA; either version 2 of the License, or
+// (at your option) any later version; incorporated herein by reference.
+//
+// -----------------------------------------------------------------------
+
+//
+// neopixel.v
+//
+// Driver for WS2812 (neopixel) LED chains
+//
+// This drives 32 output channels and expects a 25 MHz clock.
+// As long as the external RAM can keep up, the number of channels
+// should scale with clock frequency.
+//
+
+module neopixel (
+ // System signals
+ input rst_n,
+ input clk,
+ input enable,
+
+ // CPU interface to the config RAM
+ input [7:0] cpu_do,
+ input [6:0] cpu_a,
+ input cpu_wr_n,
+ input cpu_rd_n,
+ output [7:0] cpu_di,
+
+ // SRAM interface
+ output [18:0] ram_a, // BIT address into system RAM
+ input ram_q, // Expected one cycle later
+
+ // Neopixel pulse output
+ output reg [31:0] npout
+ );
+
+ // Pipeline stages:
+ // A - generate address for config/status RAM
+ // B - generate address for SRAM, advance staus RAM
+ // D - process and latch output
+ // E - pulse shaping
+
+ reg g_enable; // Global enable, latched on word boundaries
+
+ // Bit/channel counters
+ // 32 channels x 24 bits
+ reg [9:0] a_ctr;
+ reg [9:0] b_ctr;
+ reg [9:0] d_ctr;
+ reg [9:0] e_ctr;
+
+ wire [9:0] a_ctr_p1 = a_ctr + 1'b1;
+
+ always @(negedge rst_n or posedge clk)
+ if (~rst_n)
+ begin
+ a_ctr <= 10'd0;
+ b_ctr <= 10'd1;
+ d_ctr <= 10'd2;
+ e_ctr <= 10'd3;
+ g_enable <= 1'b0;
+ end
+ else
+ begin
+ // a_ctr[9:5] counts from 0 to 23 (bits per word)
+ if (&a_ctr_p1[9:8])
+ begin
+ a_ctr <= 10'b0;
+ g_enable <= enable;
+ end
+ else
+ begin
+ a_ctr <= a_ctr_p1;
+ end
+
+ b_ctr <= a_ctr;
+ d_ctr <= b_ctr;
+ e_ctr <= d_ctr;
+ end // else: !if(~rst_n)
+
+ // A stage, counter fed to RAMs
+
+ wire [7:0] conf_cpu_q;
+ wire [31:0] b_conf_q;
+
+ // Configuration RAM
+ npconfram npconfram (
+ .clock ( clk ),
+
+ .address_a ( a_ctr[4:0] ),
+ .data_a ( 32'bx ),
+ .wren_a ( 1'b0 ), // Readonly port
+ .q_a ( b_conf_q ),
+
+ .address_b ( cpu_a ),
+ .data_b ( cpu_do ),
+ .wren_b ( ~cpu_wr_n ),
+ .q_b ( conf_cpu_q )
+ );
+
+ assign cpu_di = ~cpu_rd_n ? conf_cpu_q : ~8'b0;
+
+ wire [35:0] b_stat_q;
+ reg [35:0] b_stat_d;
+
+ // Status RAM
+ npstatram npstatram (
+ .clock ( clk ),
+
+ .rdaddress ( a_ctr[4:0] ),
+ .q ( b_stat_q ),
+
+ .wraddress ( b_ctr[4:0] ),
+ .wren ( 1'b1 ),
+ .data ( b_stat_d )
+ );
+
+ // B stage, SRAM address generation
+
+ wire [15:0] b_conf_addr = b_conf_q[15:0];
+ 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];
+
+ // Output: are we in chain reset?
+ reg b_in_rst;
+
+ // Channel is enabled if plen > 0 or global disable
+ wire b_ena = |b_conf_plen & 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];
+
+ always @(*)
+ begin
+ b_stat_d[35:33] = 3'bxxx;
+ b_stat_d[32:0] = b_stat_q[32:0];
+
+ if ( ~b_ena )
+ begin
+ b_stat_d[15:0] = b_conf_addr;
+ b_stat_d[32:16] = ~9'b0;
+ end
+ else
+ begin
+ if (&b_ctr[7:5] ) // New byte?
+ 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] )
+ end // else: !if( ~b_ena )
+ end // always @ (*)
+
+ always @(negedge rst_n or posedge clk)
+ if (~rst_n)
+ b_in_rst <= 1'b1;
+ else
+ b_in_rst <= ~b_ena | b_stat_cctr[8];
+
+ // b_ctr[2:0] is inverted as bit order is bigendian
+ assign ram_a = { b_stat_addr, ~b_ctr[7:5] };
+
+ // D stage, data out from SRAM, parallel out
+ reg [31:0] d_in_rst;
+ reg [31:0] d_data;
+
+ reg [1:0] pulse;
+
+ always @(negedge rst_n or posedge clk)
+ if (~rst_n)
+ begin
+ d_in_rst <= ~32'b0;
+ d_data <= 32'bx;
+ pulse <= 2'b0;
+ end
+ else
+ begin
+ d_in_rst[d_ctr[4:0]] <= b_in_rst;
+ d_data[d_ctr[4:0]] <= ram_q;
+ pulse[0] <= (d_ctr[4:0] < 5'd8);
+ pulse[1] <= (d_ctr[4:0] < 5'd20);
+ end
+
+ // E stage, pulse generation (all channels loaded in parallel)
+
+ reg [31:0] e_in_rst;
+ reg [31:0] e_data;
+
+ always @(negedge rst_n or posedge clk)
+ if (~rst_n)
+ begin
+ e_in_rst <= ~32'b0;
+ e_data <= 32'bx;
+ end
+ else if (&e_ctr[4:0])
+ begin
+ // Parallel load of all channels
+ e_in_rst <= d_in_rst;
+ e_data <= d_data;
+ end
+
+ genvar i;
+ generate
+ for (i = 0; i < 32; i = i + 1)
+ begin: gen_npout
+ always @(negedge rst_n or posedge clk)
+ if (~rst_n)
+ npout[i] <= 1'b0;
+ else
+ npout[i] <= ~e_in_rst[i] & pulse[e_data[i]];
+ end
+ endgenerate
+endmodule // neopixel
diff --git a/npgpio.ods b/npgpio.ods
new file mode 100644
index 0000000..85c613b
--- /dev/null
+++ b/npgpio.ods
Binary files differ
diff --git a/ports.txt b/ports.txt
index c5ef5c6..7e929e3 100644
--- a/ports.txt
+++ b/ports.txt
@@ -7,10 +7,14 @@
144 - turbo
148 - LED control
149 - Green LEDs
-150 - 7seg right
-151 - 7seg left
+150 - 7seg #0 (right)
+151 - 7seg #1
152 - Red LEDs 7:0
153 - Red LEDs 9:8
+154 - 7seg #2
+155 - 7seg #3 (left)
+156 - Neopixel control address
+157 - Neopixel control data
158 - FGCTL
159 - FG 16K page select
160 - GPIO pin read 7:0