data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v
 line:54: before: "integer"
1: b'%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:84: Operator ASSIGN expects 6 bits on the Assign RHS, but Assign RHS\'s CONST \'5\'h0\' generates 5 bits.\n                                                                                               : ... In instance salsaengine\n reg [5:0] mcount = 5\'d0;  \n                    ^~~~\n                ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message.\n%Warning-WIDTHCONCAT: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:197: Unsized numbers/parameters not allowed in concatenations.\n                                                                                                      : ... In instance salsaengine\n assign rd_addr = { phase_addr+1, addrsourceSave_in ? memtop[ADDRBITS-THREADS_BITS:1] : adj_addr };  \n                              ^\n%Warning-WIDTHCONCAT: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:197: Unsized numbers/parameters not allowed in replications.\n                                                                                                      : ... In instance salsaengine\n assign rd_addr = { phase_addr+1, addrsourceSave_in ? memtop[ADDRBITS-THREADS_BITS:1] : adj_addr };  \n                                ^\n%Error: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:215: Cannot find file containing module: \'ram\'\n ram # (.ADDRBITS(ADDRBITS)) ram1_blk (rd_addr1, wr_addr1, ram_clk, ram1_din, ram_wren_d, ram1_dout);\n ^~~\n        ... Looked in:\n             data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A,data/full_repos/permissive/11584509/ram\n             data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A,data/full_repos/permissive/11584509/ram.v\n             data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A,data/full_repos/permissive/11584509/ram.sv\n             ram\n             ram.v\n             ram.sv\n             obj_dir/ram\n             obj_dir/ram.v\n             obj_dir/ram.sv\n%Error: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:216: Cannot find file containing module: \'ram\'\n ram # (.ADDRBITS(ADDRBITS)) ram2_blk (rd_addr2, wr_addr2, ram_clk, ram2_din, ram_wren_d, ram2_dout);\n ^~~\n%Error: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:217: Cannot find file containing module: \'ram\'\n ram # (.ADDRBITS(ADDRBITS)) ram3_blk (rd_addr3, wr_addr3, ram_clk, ram3_din, ram_wren_d, ram3_dout);\n ^~~\n%Error: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:218: Cannot find file containing module: \'ram\'\n ram # (.ADDRBITS(ADDRBITS)) ram4_blk (rd_addr4, wr_addr4, ram_clk, ram4_din, ram_wren_d, ram4_dout);\n ^~~\n%Error: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:224: Cannot find file containing module: \'salsa\'\n salsa salsa_blk (hash_clk, mixfeedback_d, X0, X1, Xmix, X0out, X1out, Xaddr);\n ^~~~~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:240: Bit extraction of array[7:0] requires 3 bit index, not 4 bits.\n                                                                                                : ... In instance salsaengine\n assign { mstate_in, mcount_in, writeaddr_in, cycle_in, doneROM_in, mixfeedback_in, addrsourceMix_in, addrsourceSave_in, mixspecial_in,  intcycles_in} = (phase == THREADS) ? 0 : sstate[phase];\n                                                                                                                                                                                        ^\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:240: Operator ASSIGNW expects 41 bits on the Assign RHS, but Assign RHS\'s COND generates 42 bits.\n                                                                                                : ... In instance salsaengine\n assign { mstate_in, mcount_in, writeaddr_in, cycle_in, doneROM_in, mixfeedback_in, addrsourceMix_in, addrsourceSave_in, mixspecial_in,  intcycles_in} = (phase == THREADS) ? 0 : sstate[phase];\n                                                                                                                                                       ^\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:274: Bit extraction of array[7:0] requires 3 bit index, not 4 bits.\n                                                                                                : ... In instance salsaengine\n   sstate[phase_d] <= reset ? 0 : { mstate, mcount, writeaddr, cycle, doneROM, mixfeedback, addrsourceMix,\n         ^\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:274: Operator COND expects 42 bits on the Conditional False, but Conditional False\'s REPLICATE generates 41 bits.\n                                                                                                : ... In instance salsaengine\n   sstate[phase_d] <= reset ? 0 : { mstate, mcount, writeaddr, cycle, doneROM, mixfeedback, addrsourceMix,\n                            ^\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:297: Operator ASSIGNDLY expects 3 bits on the Assign RHS, but Assign RHS\'s VARREF \'phase\' generates 4 bits.\n                                                                                                : ... In instance salsaengine\n  phase_addr_d1 <= phase;\n                ^~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:298: Operator ASSIGNDLY expects 3 bits on the Assign RHS, but Assign RHS\'s VARREF \'phase\' generates 4 bits.\n                                                                                                : ... In instance salsaengine\n  phase_addr_d2 <= phase;\n                ^~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:299: Operator ASSIGNDLY expects 3 bits on the Assign RHS, but Assign RHS\'s VARREF \'phase\' generates 4 bits.\n                                                                                                : ... In instance salsaengine\n  phase_addr_d3 <= phase;\n                ^~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:300: Operator ASSIGNDLY expects 3 bits on the Assign RHS, but Assign RHS\'s VARREF \'phase\' generates 4 bits.\n                                                                                                : ... In instance salsaengine\n  phase_addr_d4 <= phase;\n                ^~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:325: Operator EQ expects 32 or 19 bits on the LHS, but LHS\'s VARREF \'start_count\' generates 16 bits.\n                                                                                                : ... In instance salsaengine\n  if (reset || start_count == START_INTERVAL)\n                           ^~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:343: Bit extraction of array[7:0] requires 3 bit index, not 4 bits.\n                                                                                                : ... In instance salsaengine\n   nonce_sr <= snonce[phase_d];   \n                     ^\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:344: Bit extraction of array[7:0] requires 3 bit index, not 4 bits.\n                                                                                                : ... In instance salsaengine\n   snonce[phase_d] <= nonce_sr;\n         ^\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:419: Operator ASSIGNDLY expects 5 bits on the Assign RHS, but Assign RHS\'s REPLICATE generates 4 bits.\n                                                                                                : ... In instance salsaengine\n        intcycles <= { {THREADS_BITS+12-ADDRBITSX{1\'b0}}, Xaddr[12-ADDRBITSX:0] };  \n                  ^~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:422: Operator ASSIGNDLY expects 5 bits on the Assign RHS, but Assign RHS\'s REPLICATE generates 4 bits.\n                                                                                                : ... In instance salsaengine\n         intcycles <= { {THREADS_BITS+11-ADDRBITSX{1\'b0}}, 1\'b1, Xaddr[12-ADDRBITSX:0] };\n                   ^~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:489: Operator ASSIGNDLY expects 5 bits on the Assign RHS, but Assign RHS\'s REPLICATE generates 4 bits.\n                                                                                                : ... In instance salsaengine\n        intcycles <= { {THREADS_BITS+12-ADDRBITSX{1\'b0}}, Xaddr[12-ADDRBITSX:0] };  \n                  ^~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-EIGHT-A/salsaengine.v:492: Operator ASSIGNDLY expects 5 bits on the Assign RHS, but Assign RHS\'s REPLICATE generates 4 bits.\n                                                                                                : ... In instance salsaengine\n         intcycles <= { {THREADS_BITS+11-ADDRBITSX{1\'b0}}, 1\'b1, Xaddr[12-ADDRBITSX:0] };\n                   ^~\n%Error: Exiting due to 5 error(s), 18 warning(s)\n'
module salsaengine (hash_clk, reset, din, dout, shift, start, busy, result );

	input hash_clk;
	input reset;
	input din;
	input shift;
	input start;
	output busy;
	output reg result = 1'b0;
	output dout;
	





	parameter ADDRBITS = 12;




	parameter THREADS = 8;

	function integer clog2;
		input integer value;
		begin
		value = value-1;
		for (clog2=0; value>0; clog2=clog2+1)
		value = value>>1;
		end
	endfunction

	parameter THREADS_BITS = clog2(THREADS);
	

	parameter ADDRBITSX = (ADDRBITS == 13) ? ADDRBITS-1 : ADDRBITS;

	reg [THREADS_BITS:0]phase = 0;
	reg [THREADS_BITS:0]phase_d = THREADS;

	always @ (posedge hash_clk)
	begin
		phase <= (phase == THREADS) ? 0 : phase + 1;
		phase_d <= phase;
	end



	parameter XSnull = 0, XSload = 1, XSmix = 2, XSram = 4;
	reg [2:0] XCtl = XSnull;

	parameter R_IDLE=0, R_START=1, R_WRITE=2, R_MIX=4, R_INT=8;
	reg [3:0] mstate = R_IDLE;
	reg [10:0] cycle = 11'd0;
	reg [5:0] mcount = 5'd0;
	reg doneROM = 1'd0;
	reg mixfeedback = 1'b0;
	reg mixfeedback_d = 1'b0;
	reg addrsourceMix = 1'b0;
	reg addrsourceMix_d = 1'b0;
	reg addrsourceSave = 1'b0;
	reg mixspecial = 1'b0;
	reg xoren = 1'b1;
	reg [THREADS_BITS+1:0] intcycles = 0;

	wire [511:0] Xmix;
	reg [511:0] X0;
	reg [511:0] X1;
	wire [511:0] X0in;
	wire [511:0] X1in;
	wire [511:0] X0out;
	wire [511:0] X1out;
	reg [1023:0] salsaShiftReg;
	reg [31:0] nonce_sr;
	assign dout = salsaShiftReg[1023];

	reg [511:0] Xmix_d;
	reg [511:0] X1out_d;


	reg [THREADS_BITS+38:0] sstate [THREADS-1:0];
	wire [3:0] mstate_in;
	wire [10:0] cycle_in;
	wire [5:0] mcount_in;
	wire [9:0] writeaddr_in;
	wire doneROM_in;
	wire mixfeedback_in;
	wire addrsourceMix_in;
	wire addrsourceSave_in;
	wire mixspecial_in;
	wire [THREADS_BITS+1:0] intcycles_in;

	reg [31:0] snonce [THREADS-1:0];

	





	wire [1023:0] X;
	`define IDX(x) (((x)+1)*(32)-1):((x)*(32))
	genvar i;
	generate
	for (i = 0; i < 32; i = i + 1) begin : Xrewire
		wire [31:0] tmp;
		assign tmp = salsaShiftReg[`IDX(i)];
		assign X[`IDX(i)] = { tmp[7:0], tmp[15:8], tmp[23:16], tmp[31:24] };
	end
	endgenerate


	reg [9:0] writeaddr = 10'd0;




	(* S = "TRUE" *) reg [9:0] writeaddr_d1 = 10'd0;
	(* S = "TRUE" *) reg [9:0] writeaddr_d2 = 10'd0;
	(* S = "TRUE" *) reg [9:0] writeaddr_d3 = 10'd0;
	(* S = "TRUE" *) reg [9:0] writeaddr_d4 = 10'd0;
	



	
	wire [9:0] Xaddr;
	wire [ADDRBITS-1:0]rd_addr;
	(* S = "TRUE" *) wire [ADDRBITS-1:0]wr_addr1;
	(* S = "TRUE" *) wire [ADDRBITS-1:0]wr_addr2;
	(* S = "TRUE" *) wire [ADDRBITS-1:0]wr_addr3;
	(* S = "TRUE" *) wire [ADDRBITS-1:0]wr_addr4;
	wire [255:0]ram1_din;
	wire [255:0]ram1_dout;
	wire [255:0]ram2_din;
	wire [255:0]ram2_dout;
	wire [255:0]ram3_din;
	wire [255:0]ram3_dout;
	wire [255:0]ram4_din;
	wire [255:0]ram4_dout;
	wire [1023:0]ramout;

	reg ram_wren = 1'b0;
	reg ram_wren_d = 1'b0;
	wire ram_clk;
	assign ram_clk = hash_clk;
	

	
	wire [15:0] memtop = 16'hfffe;
	
	wire [ADDRBITS-THREADS_BITS-1:0] adj_addr;

	if (ADDRBITS < 13)
		assign adj_addr = (Xaddr[9:13-ADDRBITS] == memtop[9:13-ADDRBITS]) ?
							memtop[ADDRBITS-THREADS_BITS-1:0] : Xaddr[9:13-ADDRBITS];
	else
		assign adj_addr = Xaddr;
	
	wire [THREADS_BITS-1:0] phase_addr;
	(* S = "TRUE" *) reg [THREADS_BITS-1:0] phase_addr_d1;
	(* S = "TRUE" *) reg [THREADS_BITS-1:0] phase_addr_d2;
	(* S = "TRUE" *) reg [THREADS_BITS-1:0] phase_addr_d3;
	(* S = "TRUE" *) reg [THREADS_BITS-1:0] phase_addr_d4;
	
	assign phase_addr = phase[THREADS_BITS-1:0];

	assign rd_addr = { phase_addr+1, addrsourceSave_in ? memtop[ADDRBITS-THREADS_BITS:1] : adj_addr };
	
	assign wr_addr1 = { phase_addr_d1, writeaddr_d1[9:13-ADDRBITS] };
	assign wr_addr2 = { phase_addr_d2, writeaddr_d2[9:13-ADDRBITS] };
	assign wr_addr3 = { phase_addr_d3, writeaddr_d3[9:13-ADDRBITS] };
	assign wr_addr4 = { phase_addr_d4, writeaddr_d4[9:13-ADDRBITS] };


	
	(* S = "TRUE" *) reg [ADDRBITS-1:0] rd_addr_z_1 = 0;
	(* S = "TRUE" *) reg [ADDRBITS-1:0] rd_addr_z_2 = 0;
	(* S = "TRUE" *) reg [ADDRBITS-1:0] rd_addr_z_3 = 0;
	(* S = "TRUE" *) reg [ADDRBITS-1:0] rd_addr_z_4 = 0;
	(* S = "TRUE" *) wire [ADDRBITS-1:0] rd_addr1 = rd_addr | rd_addr_z_1;
	(* S = "TRUE" *) wire [ADDRBITS-1:0] rd_addr2 = rd_addr | rd_addr_z_2;
	(* S = "TRUE" *) wire [ADDRBITS-1:0] rd_addr3 = rd_addr | rd_addr_z_3;
	(* S = "TRUE" *) wire [ADDRBITS-1:0] rd_addr4 = rd_addr | rd_addr_z_4;
	
	ram # (.ADDRBITS(ADDRBITS)) ram1_blk (rd_addr1, wr_addr1, ram_clk, ram1_din, ram_wren_d, ram1_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram2_blk (rd_addr2, wr_addr2, ram_clk, ram2_din, ram_wren_d, ram2_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram3_blk (rd_addr3, wr_addr3, ram_clk, ram3_din, ram_wren_d, ram3_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram4_blk (rd_addr4, wr_addr4, ram_clk, ram4_din, ram_wren_d, ram4_dout);
	assign ramout = { ram4_dout, ram3_dout, ram2_dout, ram1_dout };
	assign { ram4_din, ram3_din, ram2_din, ram1_din } = addrsourceMix_d ? { Xmix_d, X1out_d} : { X1, X0} ;


	
	salsa salsa_blk (hash_clk, mixfeedback_d, X0, X1, Xmix, X0out, X1out, Xaddr);


	wire [511:0] Zbits;
	assign Zbits = {512{xoren}};
	

	assign X0in = (XCtl==XSmix) ? X1out : (XCtl==XSram) ? ((mixspecial ? X1out : X0out) & Zbits) ^ ramout[511:0] : (XCtl==XSload) ? X[511:0] : X0out;
	assign X1in = (XCtl==XSmix) ? Xmix : (XCtl==XSram) ? ((mixspecial ? Xmix : X1out) & Zbits) ^ ramout[1023:512] : (XCtl==XSload) ? X[1023:512] : X1out;
	





	
	assign { mstate_in, mcount_in, writeaddr_in, cycle_in, doneROM_in, mixfeedback_in, addrsourceMix_in, addrsourceSave_in, mixspecial_in,  intcycles_in} = (phase == THREADS) ? 0 : sstate[phase];



	reg busy_flag = 1'b0;

`ifdef ONETHREAD


	reg start_once = 1'b0;
	wire start_flag;
	assign start_flag = start & ~start_once;
	assign busy = busy_flag;
`else




	reg [15:0] start_count = 0;




	parameter START_INTERVAL = ((ADDRBITS == 12) ? 184320 : (ADDRBITS == 11) ? 258048 : 405504)	/ THREADS;
	reg start_flag = 1'b0;
	assign busy = busy_flag;
`endif
	
	always @ (posedge hash_clk)
	begin
		X0 <= X0in;
		X1 <= X1in;

		if (phase_d != THREADS)
			sstate[phase_d] <= reset ? 0 : { mstate, mcount, writeaddr, cycle, doneROM, mixfeedback, addrsourceMix,
												addrsourceSave, mixspecial, intcycles };
		mstate <= mstate_in;
		mcount <= mcount_in;
		writeaddr <= writeaddr_in;
		cycle <= cycle_in;
		intcycles <= intcycles_in;
		doneROM <= doneROM_in;
		mixfeedback <= mixfeedback_in;
		addrsourceMix <= addrsourceMix_in;
		addrsourceSave <= addrsourceSave_in;
		mixspecial <= mixspecial_in;
		
		mixfeedback_d <= mixfeedback;
		addrsourceMix_d <= addrsourceMix;
		ram_wren_d <= ram_wren;


		writeaddr_d1 <= addrsourceMix ? memtop[10:1] : writeaddr;
		writeaddr_d2 <= addrsourceMix ? memtop[10:1] : writeaddr;
		writeaddr_d3 <= addrsourceMix ? memtop[10:1] : writeaddr;
		writeaddr_d4 <= addrsourceMix ? memtop[10:1] : writeaddr;

		phase_addr_d1 <= phase;
		phase_addr_d2 <= phase;
		phase_addr_d3 <= phase;
		phase_addr_d4 <= phase;


		rd_addr_z_1 <= {ADDRBITS{reset}};
		rd_addr_z_2 <= {ADDRBITS{reset}};
		rd_addr_z_3 <= {ADDRBITS{reset}};
		rd_addr_z_4 <= {ADDRBITS{reset}};
		
		Xmix_d <= Xmix;
		X1out_d <= X1out;

		XCtl <= XSnull;
		addrsourceSave <= 0;
		ram_wren <= 0;
		xoren <= 1;


		`ifdef ONETHREAD
		if (start)
			start_once <= 1'b1;
		if (reset)
			start_once <= 1'b0;
		`else
		start_count <= start_count + 1;

		if (reset || start_count == START_INTERVAL)
		begin
			start_count <= 0;
			if (~reset && start)
				start_flag <= 1'b1;
		end
		`endif
		

		if (shift)
		begin
			salsaShiftReg <= { salsaShiftReg[1022:0], nonce_sr[31] };
			nonce_sr <= { nonce_sr[30:0], din };
		end
		else
		if (XCtl==XSload && phase_d != THREADS)
		begin
			salsaShiftReg <= { Xmix, X1out };
			nonce_sr <= snonce[phase_d];
			snonce[phase_d] <= nonce_sr;
		end
		
		if (reset == 1'b1)
		begin
			mstate <= R_IDLE;
			busy_flag <= 1'b0;
			result <= 1'b0;
		end
		else
		begin
			case (mstate_in)
				R_IDLE: begin



					if ((phase!=THREADS) && start_flag)
					begin
						XCtl <= XSload;
						`ifndef ONETHREAD
							start_flag <= 1'b0;
						`endif
						busy_flag <= 1'b0;

						mstate <= R_START;
					end
				end
				R_START: begin
						writeaddr <= 0;
						mcount <= 0;
						cycle <= 0;
						mixfeedback <= 1'b0;
						addrsourceMix <= 1'b0;
						mixspecial <= 1'b0;
						doneROM <= 1'b0;
						busy_flag <= 1'b1;
						result <= 1'b0;
						ram_wren <= 1'b1;
						mstate <= R_WRITE;
					end
				R_WRITE: begin
					mcount <= mcount_in + 6'd1;





					if (mcount_in==0)
					begin
						mixfeedback <= 1'b1;
						if (writeaddr_in==1023)
							doneROM <= 1'b1;
						writeaddr <= writeaddr_in + 10'd1;
					end
					if (mcount_in==4 || mcount_in==8)
						mixfeedback <= 1'b1;
					if (mcount_in==3 || mcount_in==7)
					begin
						XCtl <= XSmix;							
						mixfeedback <= 1'b0;
					end
					if (mcount_in==6 && doneROM_in)
						addrsourceMix <= 1'b1;
					if (mcount_in==7)
					begin
						mcount <= 0;
						if (doneROM_in)
						begin
							mstate <= R_MIX;
							XCtl <= XSram;
							mixspecial <= 1'b1;


							if (ADDRBITS < 13)
							begin
								intcycles <= { {THREADS_BITS+12-ADDRBITSX{1'b0}}, Xaddr[12-ADDRBITSX:0] };

								if ( Xaddr[9:13-ADDRBITSX] ==  memtop[ADDRBITSX-THREADS_BITS:1] )
									intcycles <= { {THREADS_BITS+11-ADDRBITSX{1'b0}}, 1'b1, Xaddr[12-ADDRBITSX:0] };

								if ( (Xaddr[9:13-ADDRBITSX] == memtop[ADDRBITSX-THREADS_BITS:1]) || |Xaddr[12-ADDRBITSX:0] )
								begin
									addrsourceSave <= 1'b1;
									ram_wren <= 1'b1;
									xoren <= 0;
								end
							end

						end
						else
						begin
							if (ADDRBITS < 13)
								ram_wren <= ~|writeaddr_in[12-ADDRBITSX:0];
							else
								ram_wren <= 1'b1;
						end
					end
				end
				R_MIX: begin




					mcount <= mcount_in + 6'd1;
					if (mcount_in==0)
					begin
						mixfeedback <= 1'b1;
						if (intcycles_in != 0)
							mstate <= R_INT;
					end

					if (mcount_in==4 || mcount_in==8)
						mixfeedback <= 1'b1;
					if (mcount_in==3 || mcount_in==7)
					begin
						XCtl <= XSmix;							
						mixfeedback <= 1'b0;
					end

					if (mcount_in==7)
					begin
						cycle <= cycle_in + 11'd1;
						mcount <= 0;
						if (cycle_in==1023)
						begin
							busy_flag <= 1'b0;
							if (start)
							begin
								XCtl <= XSload;


								result <= 1'b1;
								mstate <= R_START;
							end
							else
							begin
								mstate <= R_IDLE;
							end
						end
						else
						begin
							XCtl <= XSram;

							if (ADDRBITS < 13)
							begin
								intcycles <= { {THREADS_BITS+12-ADDRBITSX{1'b0}}, Xaddr[12-ADDRBITSX:0] };

								if ( Xaddr[9:13-ADDRBITSX] ==  memtop[ADDRBITSX-THREADS_BITS:1] )
									intcycles <= { {THREADS_BITS+11-ADDRBITSX{1'b0}}, 1'b1, Xaddr[12-ADDRBITSX:0] };

								if ( (Xaddr[9:13-ADDRBITSX] == memtop[ADDRBITSX-THREADS_BITS:1]) || |Xaddr[12-ADDRBITSX:0] )
								begin
									addrsourceSave <= 1'b1;
									ram_wren <= 1'b1;
									xoren <= 0;
								end
							end

						end
					end
					
				end

				R_INT: begin


					mcount <= mcount_in + 6'd1;
					if (mcount_in==4 || mcount_in==8)
						mixfeedback <= 1'b1;
					if (mcount_in==3 || mcount_in==7)
					begin
						XCtl <= XSmix;							
						mixfeedback <= 1'b0;
					end

					if (mcount_in==6)
						addrsourceSave <= 1'b1;

					if (mcount_in==7)
					begin
						if (intcycles_in==1)
							XCtl <= XSram;
					end
					if (mcount_in==8)
					begin
						intcycles <= intcycles_in - 1;
						mcount <= 1;
						if (intcycles_in==1)
							mstate <= R_MIX;

					end
				end
			endcase
		end
`ifdef SIM

	if (mstate==R_MIX && mcount==0)
		$display ("phase %d cycle %d Xmix %08x\n", phase, cycle-1, Xmix[511:480]);
`endif
	end
endmodule
module salsaengine (hash_clk, reset, din, dout, shift, start, busy, result );


	input hash_clk;
	input reset;
	input din;
	input shift;
	input start;
	output busy;
	output reg result = 1'b0;
	output dout;
	





	parameter ADDRBITS = 12;




	parameter THREADS = 8;

	function integer clog2;
		input integer value;
		begin
		value = value-1;
		for (clog2=0; value>0; clog2=clog2+1)
		value = value>>1;
		end
	endfunction

	parameter THREADS_BITS = clog2(THREADS);
	

	parameter ADDRBITSX = (ADDRBITS == 13) ? ADDRBITS-1 : ADDRBITS;

	reg [THREADS_BITS:0]phase = 0;
	reg [THREADS_BITS:0]phase_d = THREADS;

	always @ (posedge hash_clk)
	begin
		phase <= (phase == THREADS) ? 0 : phase + 1;
		phase_d <= phase;
	end



	parameter XSnull = 0, XSload = 1, XSmix = 2, XSram = 4;
	reg [2:0] XCtl = XSnull;

	parameter R_IDLE=0, R_START=1, R_WRITE=2, R_MIX=4, R_INT=8;
	reg [3:0] mstate = R_IDLE;
	reg [10:0] cycle = 11'd0;
	reg [5:0] mcount = 5'd0;
	reg doneROM = 1'd0;
	reg mixfeedback = 1'b0;
	reg mixfeedback_d = 1'b0;
	reg addrsourceMix = 1'b0;
	reg addrsourceMix_d = 1'b0;
	reg addrsourceSave = 1'b0;
	reg mixspecial = 1'b0;
	reg xoren = 1'b1;
	reg [THREADS_BITS+1:0] intcycles = 0;

	wire [511:0] Xmix;
	reg [511:0] X0;
	reg [511:0] X1;
	wire [511:0] X0in;
	wire [511:0] X1in;
	wire [511:0] X0out;
	wire [511:0] X1out;
	reg [1023:0] salsaShiftReg;
	reg [31:0] nonce_sr;
	assign dout = salsaShiftReg[1023];

	reg [511:0] Xmix_d;
	reg [511:0] X1out_d;


	reg [THREADS_BITS+38:0] sstate [THREADS-1:0];
	wire [3:0] mstate_in;
	wire [10:0] cycle_in;
	wire [5:0] mcount_in;
	wire [9:0] writeaddr_in;
	wire doneROM_in;
	wire mixfeedback_in;
	wire addrsourceMix_in;
	wire addrsourceSave_in;
	wire mixspecial_in;
	wire [THREADS_BITS+1:0] intcycles_in;

	reg [31:0] snonce [THREADS-1:0];

	





	wire [1023:0] X;
	`define IDX(x) (((x)+1)*(32)-1):((x)*(32))
	genvar i;
	generate
	for (i = 0; i < 32; i = i + 1) begin : Xrewire
		wire [31:0] tmp;
		assign tmp = salsaShiftReg[`IDX(i)];
		assign X[`IDX(i)] = { tmp[7:0], tmp[15:8], tmp[23:16], tmp[31:24] };
	end
	endgenerate


	reg [9:0] writeaddr = 10'd0;




	(* S = "TRUE" *) reg [9:0] writeaddr_d1 = 10'd0;
	(* S = "TRUE" *) reg [9:0] writeaddr_d2 = 10'd0;
	(* S = "TRUE" *) reg [9:0] writeaddr_d3 = 10'd0;
	(* S = "TRUE" *) reg [9:0] writeaddr_d4 = 10'd0;
	



	
	wire [9:0] Xaddr;
	wire [ADDRBITS-1:0]rd_addr;
	(* S = "TRUE" *) wire [ADDRBITS-1:0]wr_addr1;
	(* S = "TRUE" *) wire [ADDRBITS-1:0]wr_addr2;
	(* S = "TRUE" *) wire [ADDRBITS-1:0]wr_addr3;
	(* S = "TRUE" *) wire [ADDRBITS-1:0]wr_addr4;
	wire [255:0]ram1_din;
	wire [255:0]ram1_dout;
	wire [255:0]ram2_din;
	wire [255:0]ram2_dout;
	wire [255:0]ram3_din;
	wire [255:0]ram3_dout;
	wire [255:0]ram4_din;
	wire [255:0]ram4_dout;
	wire [1023:0]ramout;

	reg ram_wren = 1'b0;
	reg ram_wren_d = 1'b0;
	wire ram_clk;
	assign ram_clk = hash_clk;
	

	
	wire [15:0] memtop = 16'hfffe;
	
	wire [ADDRBITS-THREADS_BITS-1:0] adj_addr;

	if (ADDRBITS < 13)
		assign adj_addr = (Xaddr[9:13-ADDRBITS] == memtop[9:13-ADDRBITS]) ?
							memtop[ADDRBITS-THREADS_BITS-1:0] : Xaddr[9:13-ADDRBITS];
	else
		assign adj_addr = Xaddr;
	
	wire [THREADS_BITS-1:0] phase_addr;
	(* S = "TRUE" *) reg [THREADS_BITS-1:0] phase_addr_d1;
	(* S = "TRUE" *) reg [THREADS_BITS-1:0] phase_addr_d2;
	(* S = "TRUE" *) reg [THREADS_BITS-1:0] phase_addr_d3;
	(* S = "TRUE" *) reg [THREADS_BITS-1:0] phase_addr_d4;
	
	assign phase_addr = phase[THREADS_BITS-1:0];

	assign rd_addr = { phase_addr+1, addrsourceSave_in ? memtop[ADDRBITS-THREADS_BITS:1] : adj_addr };
	
	assign wr_addr1 = { phase_addr_d1, writeaddr_d1[9:13-ADDRBITS] };
	assign wr_addr2 = { phase_addr_d2, writeaddr_d2[9:13-ADDRBITS] };
	assign wr_addr3 = { phase_addr_d3, writeaddr_d3[9:13-ADDRBITS] };
	assign wr_addr4 = { phase_addr_d4, writeaddr_d4[9:13-ADDRBITS] };


	
	(* S = "TRUE" *) reg [ADDRBITS-1:0] rd_addr_z_1 = 0;
	(* S = "TRUE" *) reg [ADDRBITS-1:0] rd_addr_z_2 = 0;
	(* S = "TRUE" *) reg [ADDRBITS-1:0] rd_addr_z_3 = 0;
	(* S = "TRUE" *) reg [ADDRBITS-1:0] rd_addr_z_4 = 0;
	(* S = "TRUE" *) wire [ADDRBITS-1:0] rd_addr1 = rd_addr | rd_addr_z_1;
	(* S = "TRUE" *) wire [ADDRBITS-1:0] rd_addr2 = rd_addr | rd_addr_z_2;
	(* S = "TRUE" *) wire [ADDRBITS-1:0] rd_addr3 = rd_addr | rd_addr_z_3;
	(* S = "TRUE" *) wire [ADDRBITS-1:0] rd_addr4 = rd_addr | rd_addr_z_4;
	
	ram # (.ADDRBITS(ADDRBITS)) ram1_blk (rd_addr1, wr_addr1, ram_clk, ram1_din, ram_wren_d, ram1_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram2_blk (rd_addr2, wr_addr2, ram_clk, ram2_din, ram_wren_d, ram2_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram3_blk (rd_addr3, wr_addr3, ram_clk, ram3_din, ram_wren_d, ram3_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram4_blk (rd_addr4, wr_addr4, ram_clk, ram4_din, ram_wren_d, ram4_dout);
	assign ramout = { ram4_dout, ram3_dout, ram2_dout, ram1_dout };
	assign { ram4_din, ram3_din, ram2_din, ram1_din } = addrsourceMix_d ? { Xmix_d, X1out_d} : { X1, X0} ;


	
	salsa salsa_blk (hash_clk, mixfeedback_d, X0, X1, Xmix, X0out, X1out, Xaddr);


	wire [511:0] Zbits;
	assign Zbits = {512{xoren}};
	

	assign X0in = (XCtl==XSmix) ? X1out : (XCtl==XSram) ? ((mixspecial ? X1out : X0out) & Zbits) ^ ramout[511:0] : (XCtl==XSload) ? X[511:0] : X0out;
	assign X1in = (XCtl==XSmix) ? Xmix : (XCtl==XSram) ? ((mixspecial ? Xmix : X1out) & Zbits) ^ ramout[1023:512] : (XCtl==XSload) ? X[1023:512] : X1out;
	





	
	assign { mstate_in, mcount_in, writeaddr_in, cycle_in, doneROM_in, mixfeedback_in, addrsourceMix_in, addrsourceSave_in, mixspecial_in,  intcycles_in} = (phase == THREADS) ? 0 : sstate[phase];



	reg busy_flag = 1'b0;

`ifdef ONETHREAD


	reg start_once = 1'b0;
	wire start_flag;
	assign start_flag = start & ~start_once;
	assign busy = busy_flag;
`else




	reg [15:0] start_count = 0;




	parameter START_INTERVAL = ((ADDRBITS == 12) ? 184320 : (ADDRBITS == 11) ? 258048 : 405504)	/ THREADS;
	reg start_flag = 1'b0;
	assign busy = busy_flag;
`endif
	
	always @ (posedge hash_clk)
	begin
		X0 <= X0in;
		X1 <= X1in;

		if (phase_d != THREADS)
			sstate[phase_d] <= reset ? 0 : { mstate, mcount, writeaddr, cycle, doneROM, mixfeedback, addrsourceMix,
												addrsourceSave, mixspecial, intcycles };
		mstate <= mstate_in;
		mcount <= mcount_in;
		writeaddr <= writeaddr_in;
		cycle <= cycle_in;
		intcycles <= intcycles_in;
		doneROM <= doneROM_in;
		mixfeedback <= mixfeedback_in;
		addrsourceMix <= addrsourceMix_in;
		addrsourceSave <= addrsourceSave_in;
		mixspecial <= mixspecial_in;
		
		mixfeedback_d <= mixfeedback;
		addrsourceMix_d <= addrsourceMix;
		ram_wren_d <= ram_wren;


		writeaddr_d1 <= addrsourceMix ? memtop[10:1] : writeaddr;
		writeaddr_d2 <= addrsourceMix ? memtop[10:1] : writeaddr;
		writeaddr_d3 <= addrsourceMix ? memtop[10:1] : writeaddr;
		writeaddr_d4 <= addrsourceMix ? memtop[10:1] : writeaddr;

		phase_addr_d1 <= phase;
		phase_addr_d2 <= phase;
		phase_addr_d3 <= phase;
		phase_addr_d4 <= phase;


		rd_addr_z_1 <= {ADDRBITS{reset}};
		rd_addr_z_2 <= {ADDRBITS{reset}};
		rd_addr_z_3 <= {ADDRBITS{reset}};
		rd_addr_z_4 <= {ADDRBITS{reset}};
		
		Xmix_d <= Xmix;
		X1out_d <= X1out;

		XCtl <= XSnull;
		addrsourceSave <= 0;
		ram_wren <= 0;
		xoren <= 1;


		`ifdef ONETHREAD
		if (start)
			start_once <= 1'b1;
		if (reset)
			start_once <= 1'b0;
		`else
		start_count <= start_count + 1;

		if (reset || start_count == START_INTERVAL)
		begin
			start_count <= 0;
			if (~reset && start)
				start_flag <= 1'b1;
		end
		`endif
		

		if (shift)
		begin
			salsaShiftReg <= { salsaShiftReg[1022:0], nonce_sr[31] };
			nonce_sr <= { nonce_sr[30:0], din };
		end
		else
		if (XCtl==XSload && phase_d != THREADS)
		begin
			salsaShiftReg <= { Xmix, X1out };
			nonce_sr <= snonce[phase_d];
			snonce[phase_d] <= nonce_sr;
		end
		
		if (reset == 1'b1)
		begin
			mstate <= R_IDLE;
			busy_flag <= 1'b0;
			result <= 1'b0;
		end
		else
		begin
			case (mstate_in)
				R_IDLE: begin



					if ((phase!=THREADS) && start_flag)
					begin
						XCtl <= XSload;
						`ifndef ONETHREAD
							start_flag <= 1'b0;
						`endif
						busy_flag <= 1'b0;

						mstate <= R_START;
					end
				end
				R_START: begin
						writeaddr <= 0;
						mcount <= 0;
						cycle <= 0;
						mixfeedback <= 1'b0;
						addrsourceMix <= 1'b0;
						mixspecial <= 1'b0;
						doneROM <= 1'b0;
						busy_flag <= 1'b1;
						result <= 1'b0;
						ram_wren <= 1'b1;
						mstate <= R_WRITE;
					end
				R_WRITE: begin
					mcount <= mcount_in + 6'd1;





					if (mcount_in==0)
					begin
						mixfeedback <= 1'b1;
						if (writeaddr_in==1023)
							doneROM <= 1'b1;
						writeaddr <= writeaddr_in + 10'd1;
					end
					if (mcount_in==4 || mcount_in==8)
						mixfeedback <= 1'b1;
					if (mcount_in==3 || mcount_in==7)
					begin
						XCtl <= XSmix;							
						mixfeedback <= 1'b0;
					end
					if (mcount_in==6 && doneROM_in)
						addrsourceMix <= 1'b1;
					if (mcount_in==7)
					begin
						mcount <= 0;
						if (doneROM_in)
						begin
							mstate <= R_MIX;
							XCtl <= XSram;
							mixspecial <= 1'b1;


							if (ADDRBITS < 13)
							begin
								intcycles <= { {THREADS_BITS+12-ADDRBITSX{1'b0}}, Xaddr[12-ADDRBITSX:0] };

								if ( Xaddr[9:13-ADDRBITSX] ==  memtop[ADDRBITSX-THREADS_BITS:1] )
									intcycles <= { {THREADS_BITS+11-ADDRBITSX{1'b0}}, 1'b1, Xaddr[12-ADDRBITSX:0] };

								if ( (Xaddr[9:13-ADDRBITSX] == memtop[ADDRBITSX-THREADS_BITS:1]) || |Xaddr[12-ADDRBITSX:0] )
								begin
									addrsourceSave <= 1'b1;
									ram_wren <= 1'b1;
									xoren <= 0;
								end
							end

						end
						else
						begin
							if (ADDRBITS < 13)
								ram_wren <= ~|writeaddr_in[12-ADDRBITSX:0];
							else
								ram_wren <= 1'b1;
						end
					end
				end
				R_MIX: begin




					mcount <= mcount_in + 6'd1;
					if (mcount_in==0)
					begin
						mixfeedback <= 1'b1;
						if (intcycles_in != 0)
							mstate <= R_INT;
					end

					if (mcount_in==4 || mcount_in==8)
						mixfeedback <= 1'b1;
					if (mcount_in==3 || mcount_in==7)
					begin
						XCtl <= XSmix;							
						mixfeedback <= 1'b0;
					end

					if (mcount_in==7)
					begin
						cycle <= cycle_in + 11'd1;
						mcount <= 0;
						if (cycle_in==1023)
						begin
							busy_flag <= 1'b0;
							if (start)
							begin
								XCtl <= XSload;


								result <= 1'b1;
								mstate <= R_START;
							end
							else
							begin
								mstate <= R_IDLE;
							end
						end
						else
						begin
							XCtl <= XSram;

							if (ADDRBITS < 13)
							begin
								intcycles <= { {THREADS_BITS+12-ADDRBITSX{1'b0}}, Xaddr[12-ADDRBITSX:0] };

								if ( Xaddr[9:13-ADDRBITSX] ==  memtop[ADDRBITSX-THREADS_BITS:1] )
									intcycles <= { {THREADS_BITS+11-ADDRBITSX{1'b0}}, 1'b1, Xaddr[12-ADDRBITSX:0] };

								if ( (Xaddr[9:13-ADDRBITSX] == memtop[ADDRBITSX-THREADS_BITS:1]) || |Xaddr[12-ADDRBITSX:0] )
								begin
									addrsourceSave <= 1'b1;
									ram_wren <= 1'b1;
									xoren <= 0;
								end
							end

						end
					end
					
				end

				R_INT: begin


					mcount <= mcount_in + 6'd1;
					if (mcount_in==4 || mcount_in==8)
						mixfeedback <= 1'b1;
					if (mcount_in==3 || mcount_in==7)
					begin
						XCtl <= XSmix;							
						mixfeedback <= 1'b0;
					end

					if (mcount_in==6)
						addrsourceSave <= 1'b1;

					if (mcount_in==7)
					begin
						if (intcycles_in==1)
							XCtl <= XSram;
					end
					if (mcount_in==8)
					begin
						intcycles <= intcycles_in - 1;
						mcount <= 1;
						if (intcycles_in==1)
							mstate <= R_MIX;

					end
				end
			endcase
		end
`ifdef SIM

	if (mstate==R_MIX && mcount==0)
		$display ("phase %d cycle %d Xmix %08x\n", phase, cycle-1, Xmix[511:480]);
`endif
	end
endmodule