// This is a component of pluto_servo, a PWM servo driver and quadrature // counter for emc2 // Copyright 2006 Jeff Epler // // 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; either version 2 of the License, or // (at your option) any later version. // // This program 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 this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. module main(clk, led, nConfig, epp_nReset, pport_data, nWrite, nWait, nDataStr, nAddrStr, dout, din, step, dir); parameter W=10; parameter F=11; parameter T=4; input clk; output led, nConfig; inout [7:0] pport_data; input nWrite; output nWait; input nDataStr, nAddrStr, epp_nReset; input [15:0] din; reg Spolarity; reg[13:0] real_dout; output [13:0] dout = do_tristate ? 14'bZ : real_dout; wire[3:0] real_step; output [3:0] step = do_tristate ? 4'bZ : real_step ^ {4{Spolarity}}; wire[3:0] real_dir; output [3:0] dir = do_tristate ? 4'bZ : real_dir; wire [W+F-1:0] pos0, pos1, pos2, pos3; reg [F:0] vel0, vel1, vel2, vel3; reg [T-1:0] dirtime, steptime; reg [1:0] tap; reg [10:0] div2048; wire stepcnt = ~|(div2048[5:0]); always @(posedge clk) begin div2048 <= div2048 + 1'd1; end wire do_enable_wdt, do_tristate; wdt w(clk, do_enable_wdt, &div2048, do_tristate); stepgen #(W,F,T) s0(clk, stepcnt, pos0, vel0, dirtime, steptime, real_step[0], real_dir[0], tap); stepgen #(W,F,T) s1(clk, stepcnt, pos1, vel1, dirtime, steptime, real_step[1], real_dir[1], tap); stepgen #(W,F,T) s2(clk, stepcnt, pos2, vel2, dirtime, steptime, real_step[2], real_dir[2], tap); stepgen #(W,F,T) s3(clk, stepcnt, pos3, vel3, dirtime, steptime, real_step[3], real_dir[3], tap); // EPP stuff wire EPP_write = ~nWrite; wire EPP_read = nWrite; wire EPP_addr_strobe = ~nAddrStr; wire EPP_data_strobe = ~nDataStr; wire EPP_strobe = EPP_data_strobe | EPP_addr_strobe; wire EPP_wait; assign nWait = ~EPP_wait; wire [7:0] EPP_datain = pport_data; wire [7:0] EPP_dataout; assign pport_data = EPP_dataout; reg [4:0] EPP_strobe_reg; always @(posedge clk) EPP_strobe_reg <= {EPP_strobe_reg[3:0], EPP_strobe}; wire EPP_strobe_edge1 = (EPP_strobe_reg[2:1]==2'b01); // reg led; assign EPP_wait = EPP_strobe_reg[4]; wire[15:0] EPP_dataword = {EPP_datain, lowbyte}; reg[4:0] addr_reg; reg[7:0] lowbyte; always @(posedge clk) if(EPP_strobe_edge1 & EPP_write & EPP_addr_strobe) begin addr_reg <= EPP_datain[4:0]; end else if(EPP_strobe_edge1 & !EPP_addr_strobe) addr_reg <= addr_reg + 4'd1; always @(posedge clk) begin if(EPP_strobe_edge1 & EPP_write & EPP_data_strobe) begin if(addr_reg[3:0] == 4'd1) vel0 <= EPP_dataword[F:0]; else if(addr_reg[3:0] == 4'd3) vel1 <= EPP_dataword[F:0]; else if(addr_reg[3:0] == 4'd5) vel2 <= EPP_dataword[F:0]; else if(addr_reg[3:0] == 4'd7) vel3 <= EPP_dataword[F:0]; else if(addr_reg[3:0] == 4'd9) begin real_dout <= { EPP_datain[5:0], lowbyte }; end else if(addr_reg[3:0] == 4'd11) begin tap <= lowbyte[7:6]; steptime <= lowbyte[T-1:0]; Spolarity <= EPP_datain[7]; // EPP_datain[6] is do_enable_wdt dirtime <= EPP_datain[T-1:0]; end else lowbyte <= EPP_datain; end end reg [31:0] data_buf; always @(posedge clk) begin if(EPP_strobe_edge1 & EPP_read && addr_reg[1:0] == 2'd0) begin if(addr_reg[4:2] == 3'd0) data_buf <= pos0; else if(addr_reg[4:2] == 3'd1) data_buf <= pos1; else if(addr_reg[4:2] == 3'd2) data_buf <= pos2; else if(addr_reg[4:2] == 3'd3) data_buf <= pos3; else if(addr_reg[4:2] == 3'd4) data_buf <= din; end end // the addr_reg test looks funny because it is auto-incremented in an always // block so "1" reads the low byte, "2 and "3" read middle bytes, and "0" // reads the high byte I have a feeling that I'm doing this in the wrong way. wire [7:0] data_reg = addr_reg[1:0] == 2'd1 ? data_buf[7:0] : (addr_reg[1:0] == 2'd2 ? data_buf[15:8] : (addr_reg[1:0] == 2'd3 ? data_buf[23:16] : data_buf[31:24])); wire [7:0] EPP_data_mux = data_reg; assign EPP_dataout = (EPP_read & EPP_wait) ? EPP_data_mux : 8'hZZ; // assign do_enable_wdt = EPP_strobe_edge1 & EPP_write & EPP_data_strobe & (addr_reg[3:0] == 4'd9) & EPP_datain[6]; // assign led = do_tristate ? 1'BZ : (real_step[0] ^ real_dir[0]); assign led = do_tristate ? 1'bZ : (real_step[0] ^ real_dir[0]); assign nConfig = epp_nReset; // 1'b1; assign do_enable_wdt = EPP_strobe_edge1 & EPP_write & EPP_data_strobe & (addr_reg[3:0] == 4'd9) & EPP_datain[6]; endmodule