data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A/salsaengine.v
 line:60: before: "integer"
1: b'%Error: data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A/salsaengine.v:217: Cannot find file containing module: \'ram\'\n ram # (.ADDRBITS(ADDRBITS)) ram1_blk (rd_addr1, wr_addr1, ram_clk, ram1_din, ram_wren, ram1_dout);\n ^~~\n        ... Looked in:\n             data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A,data/full_repos/permissive/11584509/ram\n             data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A,data/full_repos/permissive/11584509/ram.v\n             data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-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-SIXTYFOUR-A/salsaengine.v:218: Cannot find file containing module: \'ram\'\n ram # (.ADDRBITS(ADDRBITS)) ram2_blk (rd_addr2, wr_addr2, ram_clk, ram2_din, ram_wren, ram2_dout);\n ^~~\n%Error: data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A/salsaengine.v:219: Cannot find file containing module: \'ram\'\n ram # (.ADDRBITS(ADDRBITS)) ram3_blk (rd_addr3, wr_addr3, ram_clk, ram3_din, ram_wren, ram3_dout);\n ^~~\n%Error: data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A/salsaengine.v:220: Cannot find file containing module: \'ram\'\n ram # (.ADDRBITS(ADDRBITS)) ram4_blk (rd_addr4, wr_addr4, ram_clk, ram4_din, ram_wren, ram4_dout);\n ^~~\n%Error: data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A/salsaengine.v:228: Cannot find file containing module: \'salsa\'\n salsa salsa_blk (hash_clk, X0, X1, Xmix, X0out, Xaddr);\n ^~~~~\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A/salsaengine.v:245: Bit extraction of array[63:0] requires 6 bit index, not 7 bits.\n                                                                                                    : ... In instance salsaengine\n    (phase == THREADS ) ? 0 : sstate[phase]; \n                                    ^\n                ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message.\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A/salsaengine.v:283: Bit extraction of array[63:0] requires 6 bit index, not 7 bits.\n                                                                                                    : ... In instance salsaengine\n   sstate[phase_d] <= fsmreset ? 0 : { mstate, writeaddr, cycle, doneROM, addrwriteMix, addrreadInit, addrreadSave, intcycles };\n         ^\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A/salsaengine.v:335: Bit extraction of array[63:0] requires 6 bit index, not 7 bits.\n                                                                                                    : ... In instance salsaengine\n   nonce_sr <= snonce[phase_d];   \n                     ^\n%Warning-WIDTH: data/full_repos/permissive/11584509/experimental/LX150-SIXTYFOUR-A/salsaengine.v:336: Bit extraction of array[63:0] requires 6 bit index, not 7 bits.\n                                                                                                    : ... In instance salsaengine\n   snonce[phase_d] <= nonce_sr;\n         ^\n%Error: Exiting due to 5 error(s), 4 warning(s)\n'
module salsaengine (hash_clk, reset, din, dout, shift, start, busy, result );


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

	parameter SBITS = 8;
	input [SBITS-1:0] din;
	output [SBITS-1:0] dout;









	parameter ADDRBITS = 12;




	parameter THREADS = 64;

	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);
	
	reg [THREADS_BITS:0]phase = 0;
	reg [THREADS_BITS:0]phase_d = THREADS;
	reg reset_d=0, fsmreset=0, start_d=0, fsmstart=0;

	always @ (posedge hash_clk)
	begin
		phase <= (phase == THREADS) ? 0 : phase + 1;
		phase_d <= phase;
		reset_d <= reset;
		fsmreset <= reset_d;
		start_d <= start;
		fsmstart <= start_d;
	end



	parameter XSmix = 0, XSload = 1, XSram = 2;

	reg [1:0] XCtl = XSmix;

	parameter R_IDLE=0, R_START=1, R_LOAD=2, R_WRITE=3, R_MIX=4, R_INT=5, R_WAIT=6;
	reg [2:0] mstate = R_IDLE;
	reg [10:0] cycle = 11'd0;
	reg doneROM = 1'd0;
	reg addrwriteMix = 1'b0;
	reg addrreadInit = 1'b0;
	reg addrreadSave = 1'b0;
	reg xoren = 1'b0;


	parameter INT_BITS = THREADS_BITS - ADDRBITS + 10;

	parameter INT_BITX = (INT_BITS > 0) ? INT_BITS : INT_BITS+1;

	reg [INT_BITS: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;
	reg [1023:0] salsaShiftReg;
	reg [31:0] nonce_sr;
	assign dout = salsaShiftReg[1023:1024-SBITS];


	reg [INT_BITS+28:0] sstate [THREADS-1:0];

	wire [2:0] mstate_in;
	wire [10:0] cycle_in;
	wire [9:0] writeaddr_in;
	wire doneROM_in;
	wire addrwriteMix_in;
	wire addrreadInit_in;
	wire addrreadSave_in;
	wire [INT_BITS:0] intcycles_in;

	wire [9:0] writeaddr_next = writeaddr_in + 10'd1;

	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


	(* S = "TRUE" *) reg [9:0] writeaddr = 10'd0;
	



	
	wire [9:0] Xaddr;
	wire [ADDRBITS-1:0]rd_addr;
	wire [ADDRBITS-1:0]wr_addr1;
	wire [ADDRBITS-1:0]wr_addr2;
	wire [ADDRBITS-1:0]wr_addr3;
	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;

	(* S = "TRUE" *) reg ram_wren = 1'b0;
	wire ram_clk;
	assign ram_clk = hash_clk;
	

	
	wire [15:0] memtop = 16'hfffe;
	
	wire [9-INT_BITS:0] adj_addr;

	if (INT_BITS > 0)
		assign adj_addr = (Xaddr[9:INT_BITS] == memtop[9:INT_BITS]) ?
							memtop[9-INT_BITS:0] : Xaddr[9:INT_BITS];
	else
		assign adj_addr = Xaddr;
	
	wire [THREADS_BITS-1:0] phase_addr;
	assign phase_addr = phase[THREADS_BITS-1:0];
	reg [THREADS_BITS-1:0] phase_addr_d = 0;

	assign rd_addr = { phase_addr,
						(addrreadSave_in | addrreadInit_in) ?
							(addrreadInit_in ? {ADDRBITS-THREADS_BITS{1'b0}} : memtop[ADDRBITS-THREADS_BITS:1])
						:
							adj_addr };
		
	wire [9:0] writeaddr_adj = addrwriteMix ? memtop[10:1] : writeaddr;
	
	assign wr_addr1 = { phase_addr_d, writeaddr_adj[9:INT_BITS] };
	assign wr_addr2 = { phase_addr_d, writeaddr_adj[9:INT_BITS] };
	assign wr_addr3 = { phase_addr_d, writeaddr_adj[9:INT_BITS] };
	assign wr_addr4 = { phase_addr_d, writeaddr_adj[9:INT_BITS] };


	
	(* 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, ram1_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram2_blk (rd_addr2, wr_addr2, ram_clk, ram2_din, ram_wren, ram2_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram3_blk (rd_addr3, wr_addr3, ram_clk, ram3_din, ram_wren, ram3_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram4_blk (rd_addr4, wr_addr4, ram_clk, ram4_din, ram_wren, ram4_dout);
	assign ramout = { ram4_dout, ram3_dout, ram2_dout, ram1_dout };


	assign { ram4_din, ram3_din, ram2_din, ram1_din } = XCtl[0] ? X : { Xmix, X0out};
	

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


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

	assign X0in =  XCtl[1] ? (X0out & Zbits) ^ ramout[511:0]    : X0out;
	assign X1in =  XCtl[1] ? (Xmix  & Zbits) ^ ramout[1023:512] : Xmix;







	assign { mstate_in, writeaddr_in, cycle_in, doneROM_in, addrwriteMix_in, addrreadInit_in, addrreadSave_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 = fsmstart & ~start_once;
	assign busy = busy_flag;
`else




	reg [15:0] start_count = 0;







	parameter START_INTERVAL = (THREADS+1) * 1024 * ((1 << (15-ADDRBITS)) * THREADS / 32 + 3) / THREADS / 2;

	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] <= fsmreset ? 0 : { mstate, writeaddr, cycle, doneROM, addrwriteMix, addrreadInit, addrreadSave, intcycles };

		mstate <= mstate_in;
		writeaddr <= writeaddr_in;
		cycle <= cycle_in;
		intcycles <= intcycles_in;
		doneROM <= doneROM_in;
		addrwriteMix <= addrwriteMix_in;
		addrreadInit <= addrreadInit_in;
		addrreadSave <= addrreadSave_in;
		

		rd_addr_z_1 <= {ADDRBITS{fsmreset}};
		rd_addr_z_2 <= {ADDRBITS{fsmreset}};
		rd_addr_z_3 <= {ADDRBITS{fsmreset}};
		rd_addr_z_4 <= {ADDRBITS{fsmreset}};

		phase_addr_d <= phase[THREADS_BITS-1:0];
		
		XCtl <= XSmix;
		addrreadInit <= 1'b0;
		addrreadSave <= 1'b0;
		ram_wren <= 1'b0;
		xoren <= 1'b1;
		

		`ifdef ONETHREAD
		if (fsmstart && phase!=THREADS)
			start_once <= 1'b1;
		if (fsmreset)
			start_once <= 1'b0;
		`else
		start_count <= start_count + 1;

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

		if (shift)
		begin
			salsaShiftReg <= { salsaShiftReg[1023-SBITS:0], nonce_sr[31:32-SBITS] };
			nonce_sr <= { nonce_sr[31-SBITS:0], din};
		end
		else
		if (XCtl[0] && phase_d != THREADS)
		begin
			salsaShiftReg <= ramout;
			nonce_sr <= snonce[phase_d];
			snonce[phase_d] <= nonce_sr;
		end
		
		if (fsmreset == 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
						`ifndef ONETHREAD
							start_flag <= 1'b0;
						`endif
						busy_flag <= 1'b0;

						mstate <= R_START;



						writeaddr <= 0;
						addrwriteMix <= 1'b0;
						ram_wren <= 1'b1;


						XCtl <= XSload;
						addrreadInit <= 1'b1;
					end
				end

				R_START: begin
					XCtl <= XSram;
					xoren <= 1'b0;
					cycle <= 0;
					doneROM <= 1'b0;
					busy_flag <= 1'b1;
					result <= 1'b0;
					mstate <= R_LOAD;
				end

				R_LOAD: begin
					writeaddr <= writeaddr_next;
					if (INT_BITS == 0)
						ram_wren <= 1'b1;
					mstate <= R_WRITE;
				end

				R_WRITE: begin
					writeaddr <= writeaddr_next;

					if (writeaddr_in==1022)
						doneROM <= 1'b1;
					
					if (doneROM_in)
					begin
						addrwriteMix <= 1'b1;
						mstate <= R_MIX;
						XCtl <= XSram;


						if (INT_BITS > 0)
						begin
							intcycles <= { 1'b0, Xaddr[INT_BITX-1:0] };
							if ( Xaddr[9:INT_BITX] ==  memtop[10-INT_BITX:1] )
								intcycles <= { 1'b1, Xaddr[INT_BITX-1:0] };

							if ( (Xaddr[9:INT_BITX] == memtop[10-INT_BITX:1]) || |Xaddr[INT_BITX-1:0] )
							begin
								ram_wren <= 1'b1;
								xoren <= 1'b0;
								mstate <= R_INT;
							end

							if ( 
								( Xaddr[INT_BITX-1:0] == 1 ) &&
								!( Xaddr[9:INT_BITX] ==  memtop[10-INT_BITX:1] )
								)
									addrreadSave <= 1'b1;
						end

					end
					else
					begin
						ram_wren <=	(INT_BITS > 0) ? ~|writeaddr_next[INT_BITX-1:0] : 1'b1;					
					end
				end

				R_MIX: begin

					cycle <= cycle_in + 11'd1;
					if (cycle_in==1023)
					begin

						mstate <= R_WAIT;
						addrreadSave <= 1'b1;
						ram_wren <= 1'b1;
					end
					else
					begin
						XCtl <= XSram;

						if (INT_BITS > 0)
						begin
							intcycles <= { 1'b0, Xaddr[INT_BITX-1:0] };
							if ( Xaddr[9:INT_BITX] ==  memtop[10-INT_BITX:1] )
								intcycles <= { 1'b1, Xaddr[INT_BITX-1:0] };

							if ( (Xaddr[9:INT_BITX] == memtop[10-INT_BITX:1]) || |Xaddr[INT_BITX-1:0] )
							begin
								ram_wren <= 1'b1;
								xoren <= 1'b0;
								mstate <= R_INT;
							end

							if ( 
								( Xaddr[INT_BITX-1:0] == 1 ) &&
								!( Xaddr[9:INT_BITX] ==  memtop[10-INT_BITX:1] )
								)
									addrreadSave <= 1'b1;
						end

					end
				end

				R_INT: begin
					intcycles <= intcycles_in - 1;
					if (intcycles_in==2)
						addrreadSave <= 1'b1;
					if (intcycles_in==1)
					begin
						XCtl <= XSram;
						mstate <= R_MIX;
					end

				end

				R_WAIT: begin
						if (fsmstart)
						begin

							busy_flag <= 1'b0;
							result <= 1'b1;
							mstate <= R_START;



							writeaddr <= 0;
							addrwriteMix <= 1'b0;
							ram_wren <= 1'b1;
							

							XCtl <= XSload;
							addrreadInit <= 1'b1;
						end
						else
							addrreadSave <= 1'b1;
				end
			endcase
		end
`ifdef SIM

	if (mstate==R_MIX)
		$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 shift;
	input start;
	output busy;
	output reg result = 1'b0;

	parameter SBITS = 8;
	input [SBITS-1:0] din;
	output [SBITS-1:0] dout;









	parameter ADDRBITS = 12;




	parameter THREADS = 64;

	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);
	
	reg [THREADS_BITS:0]phase = 0;
	reg [THREADS_BITS:0]phase_d = THREADS;
	reg reset_d=0, fsmreset=0, start_d=0, fsmstart=0;

	always @ (posedge hash_clk)
	begin
		phase <= (phase == THREADS) ? 0 : phase + 1;
		phase_d <= phase;
		reset_d <= reset;
		fsmreset <= reset_d;
		start_d <= start;
		fsmstart <= start_d;
	end



	parameter XSmix = 0, XSload = 1, XSram = 2;

	reg [1:0] XCtl = XSmix;

	parameter R_IDLE=0, R_START=1, R_LOAD=2, R_WRITE=3, R_MIX=4, R_INT=5, R_WAIT=6;
	reg [2:0] mstate = R_IDLE;
	reg [10:0] cycle = 11'd0;
	reg doneROM = 1'd0;
	reg addrwriteMix = 1'b0;
	reg addrreadInit = 1'b0;
	reg addrreadSave = 1'b0;
	reg xoren = 1'b0;


	parameter INT_BITS = THREADS_BITS - ADDRBITS + 10;

	parameter INT_BITX = (INT_BITS > 0) ? INT_BITS : INT_BITS+1;

	reg [INT_BITS: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;
	reg [1023:0] salsaShiftReg;
	reg [31:0] nonce_sr;
	assign dout = salsaShiftReg[1023:1024-SBITS];


	reg [INT_BITS+28:0] sstate [THREADS-1:0];

	wire [2:0] mstate_in;
	wire [10:0] cycle_in;
	wire [9:0] writeaddr_in;
	wire doneROM_in;
	wire addrwriteMix_in;
	wire addrreadInit_in;
	wire addrreadSave_in;
	wire [INT_BITS:0] intcycles_in;

	wire [9:0] writeaddr_next = writeaddr_in + 10'd1;

	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


	(* S = "TRUE" *) reg [9:0] writeaddr = 10'd0;
	



	
	wire [9:0] Xaddr;
	wire [ADDRBITS-1:0]rd_addr;
	wire [ADDRBITS-1:0]wr_addr1;
	wire [ADDRBITS-1:0]wr_addr2;
	wire [ADDRBITS-1:0]wr_addr3;
	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;

	(* S = "TRUE" *) reg ram_wren = 1'b0;
	wire ram_clk;
	assign ram_clk = hash_clk;
	

	
	wire [15:0] memtop = 16'hfffe;
	
	wire [9-INT_BITS:0] adj_addr;

	if (INT_BITS > 0)
		assign adj_addr = (Xaddr[9:INT_BITS] == memtop[9:INT_BITS]) ?
							memtop[9-INT_BITS:0] : Xaddr[9:INT_BITS];
	else
		assign adj_addr = Xaddr;
	
	wire [THREADS_BITS-1:0] phase_addr;
	assign phase_addr = phase[THREADS_BITS-1:0];
	reg [THREADS_BITS-1:0] phase_addr_d = 0;

	assign rd_addr = { phase_addr,
						(addrreadSave_in | addrreadInit_in) ?
							(addrreadInit_in ? {ADDRBITS-THREADS_BITS{1'b0}} : memtop[ADDRBITS-THREADS_BITS:1])
						:
							adj_addr };
		
	wire [9:0] writeaddr_adj = addrwriteMix ? memtop[10:1] : writeaddr;
	
	assign wr_addr1 = { phase_addr_d, writeaddr_adj[9:INT_BITS] };
	assign wr_addr2 = { phase_addr_d, writeaddr_adj[9:INT_BITS] };
	assign wr_addr3 = { phase_addr_d, writeaddr_adj[9:INT_BITS] };
	assign wr_addr4 = { phase_addr_d, writeaddr_adj[9:INT_BITS] };


	
	(* 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, ram1_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram2_blk (rd_addr2, wr_addr2, ram_clk, ram2_din, ram_wren, ram2_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram3_blk (rd_addr3, wr_addr3, ram_clk, ram3_din, ram_wren, ram3_dout);
	ram # (.ADDRBITS(ADDRBITS)) ram4_blk (rd_addr4, wr_addr4, ram_clk, ram4_din, ram_wren, ram4_dout);
	assign ramout = { ram4_dout, ram3_dout, ram2_dout, ram1_dout };


	assign { ram4_din, ram3_din, ram2_din, ram1_din } = XCtl[0] ? X : { Xmix, X0out};
	

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


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

	assign X0in =  XCtl[1] ? (X0out & Zbits) ^ ramout[511:0]    : X0out;
	assign X1in =  XCtl[1] ? (Xmix  & Zbits) ^ ramout[1023:512] : Xmix;







	assign { mstate_in, writeaddr_in, cycle_in, doneROM_in, addrwriteMix_in, addrreadInit_in, addrreadSave_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 = fsmstart & ~start_once;
	assign busy = busy_flag;
`else




	reg [15:0] start_count = 0;







	parameter START_INTERVAL = (THREADS+1) * 1024 * ((1 << (15-ADDRBITS)) * THREADS / 32 + 3) / THREADS / 2;

	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] <= fsmreset ? 0 : { mstate, writeaddr, cycle, doneROM, addrwriteMix, addrreadInit, addrreadSave, intcycles };

		mstate <= mstate_in;
		writeaddr <= writeaddr_in;
		cycle <= cycle_in;
		intcycles <= intcycles_in;
		doneROM <= doneROM_in;
		addrwriteMix <= addrwriteMix_in;
		addrreadInit <= addrreadInit_in;
		addrreadSave <= addrreadSave_in;
		

		rd_addr_z_1 <= {ADDRBITS{fsmreset}};
		rd_addr_z_2 <= {ADDRBITS{fsmreset}};
		rd_addr_z_3 <= {ADDRBITS{fsmreset}};
		rd_addr_z_4 <= {ADDRBITS{fsmreset}};

		phase_addr_d <= phase[THREADS_BITS-1:0];
		
		XCtl <= XSmix;
		addrreadInit <= 1'b0;
		addrreadSave <= 1'b0;
		ram_wren <= 1'b0;
		xoren <= 1'b1;
		

		`ifdef ONETHREAD
		if (fsmstart && phase!=THREADS)
			start_once <= 1'b1;
		if (fsmreset)
			start_once <= 1'b0;
		`else
		start_count <= start_count + 1;

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

		if (shift)
		begin
			salsaShiftReg <= { salsaShiftReg[1023-SBITS:0], nonce_sr[31:32-SBITS] };
			nonce_sr <= { nonce_sr[31-SBITS:0], din};
		end
		else
		if (XCtl[0] && phase_d != THREADS)
		begin
			salsaShiftReg <= ramout;
			nonce_sr <= snonce[phase_d];
			snonce[phase_d] <= nonce_sr;
		end
		
		if (fsmreset == 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
						`ifndef ONETHREAD
							start_flag <= 1'b0;
						`endif
						busy_flag <= 1'b0;

						mstate <= R_START;



						writeaddr <= 0;
						addrwriteMix <= 1'b0;
						ram_wren <= 1'b1;


						XCtl <= XSload;
						addrreadInit <= 1'b1;
					end
				end

				R_START: begin
					XCtl <= XSram;
					xoren <= 1'b0;
					cycle <= 0;
					doneROM <= 1'b0;
					busy_flag <= 1'b1;
					result <= 1'b0;
					mstate <= R_LOAD;
				end

				R_LOAD: begin
					writeaddr <= writeaddr_next;
					if (INT_BITS == 0)
						ram_wren <= 1'b1;
					mstate <= R_WRITE;
				end

				R_WRITE: begin
					writeaddr <= writeaddr_next;

					if (writeaddr_in==1022)
						doneROM <= 1'b1;
					
					if (doneROM_in)
					begin
						addrwriteMix <= 1'b1;
						mstate <= R_MIX;
						XCtl <= XSram;


						if (INT_BITS > 0)
						begin
							intcycles <= { 1'b0, Xaddr[INT_BITX-1:0] };
							if ( Xaddr[9:INT_BITX] ==  memtop[10-INT_BITX:1] )
								intcycles <= { 1'b1, Xaddr[INT_BITX-1:0] };

							if ( (Xaddr[9:INT_BITX] == memtop[10-INT_BITX:1]) || |Xaddr[INT_BITX-1:0] )
							begin
								ram_wren <= 1'b1;
								xoren <= 1'b0;
								mstate <= R_INT;
							end

							if ( 
								( Xaddr[INT_BITX-1:0] == 1 ) &&
								!( Xaddr[9:INT_BITX] ==  memtop[10-INT_BITX:1] )
								)
									addrreadSave <= 1'b1;
						end

					end
					else
					begin
						ram_wren <=	(INT_BITS > 0) ? ~|writeaddr_next[INT_BITX-1:0] : 1'b1;					
					end
				end

				R_MIX: begin

					cycle <= cycle_in + 11'd1;
					if (cycle_in==1023)
					begin

						mstate <= R_WAIT;
						addrreadSave <= 1'b1;
						ram_wren <= 1'b1;
					end
					else
					begin
						XCtl <= XSram;

						if (INT_BITS > 0)
						begin
							intcycles <= { 1'b0, Xaddr[INT_BITX-1:0] };
							if ( Xaddr[9:INT_BITX] ==  memtop[10-INT_BITX:1] )
								intcycles <= { 1'b1, Xaddr[INT_BITX-1:0] };

							if ( (Xaddr[9:INT_BITX] == memtop[10-INT_BITX:1]) || |Xaddr[INT_BITX-1:0] )
							begin
								ram_wren <= 1'b1;
								xoren <= 1'b0;
								mstate <= R_INT;
							end

							if ( 
								( Xaddr[INT_BITX-1:0] == 1 ) &&
								!( Xaddr[9:INT_BITX] ==  memtop[10-INT_BITX:1] )
								)
									addrreadSave <= 1'b1;
						end

					end
				end

				R_INT: begin
					intcycles <= intcycles_in - 1;
					if (intcycles_in==2)
						addrreadSave <= 1'b1;
					if (intcycles_in==1)
					begin
						XCtl <= XSram;
						mstate <= R_MIX;
					end

				end

				R_WAIT: begin
						if (fsmstart)
						begin

							busy_flag <= 1'b0;
							result <= 1'b1;
							mstate <= R_START;



							writeaddr <= 0;
							addrwriteMix <= 1'b0;
							ram_wren <= 1'b1;
							

							XCtl <= XSload;
							addrreadInit <= 1'b1;
						end
						else
							addrreadSave <= 1'b1;
				end
			endcase
		end
`ifdef SIM

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