wbgen_regbank.lua 29.8 KB
Newer Older
twlostow's avatar
twlostow committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
-- -*- Mode: LUA; tab-width: 2 -*-

-- wbgen2 - a simple Wishbone slave generator
-- (c) 2010 Tomasz Wlostowski
-- CERN BE-Co-HT
-- LICENSED UNDER GPL v2

function gen_hdl_field_prefix(field, reg)
	local field_count;

	if(reg.hdl_prefix == nil) then
		die("no prefix specified for reg: "..reg.name);
	end

	field_count = 0;
	foreach_subfield(reg, function(field, reg) field_count = field_count+1; end );

	if(field.count == 0) then
		die("empty reg: "..reg.name);
	end
		
	if(field.hdl_prefix == nil) then
		if(field_count >1 ) then die("multiple anonymous-prefix fields declared for reg: "..reg.name); end
		return  string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix);
	end


  
	return  string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix.."_"..field.hdl_prefix);

end

33 34 35
function gen_reset_value(field)
  return csel(field.reset_value == nil, '0', field.reset_value)
end
twlostow's avatar
twlostow committed
36 37 38 39 40 41 42 43 44 45 46 47
-- generates VHDL for monostable-type field (both same-clock and other-clock)
function gen_hdl_code_monostable(field, reg)
	local prefix = gen_hdl_field_prefix(field, reg); 

--	field.prefix = prefix;

-- monostable type field using WB bus clock
  if(field.clock == nil) then
-- WB-synchronous monostable port (bus write-only)
		field.signals = 	{	signal(BIT, 0, prefix.."_dly0"),
												signal(BIT, 0, prefix.."_int") };
					
48
		field.ports =		{	port(BIT, 0, "out", prefix.."_o", "Port for MONOSTABLE field: '"..field.name.."' in reg: '"..reg.name.."'", VPORT_REG ) };
twlostow's avatar
twlostow committed
49 50
		field.acklen = 3;

51
		field.extra_code = vsyncprocess("clk_sys_i", "rst_n_i", {
twlostow's avatar
twlostow committed
52 53 54 55 56 57 58 59 60 61 62
												 vreset (0, {
													va(prefix.."_dly0", 0);
													va(prefix.."_o", 0);
												 });
												 vposedge {
													va(prefix.."_dly0", prefix.."_int");
													va(prefix.."_o", vand(prefix.."_int", vnot(prefix.."_dly0")));
												 };
												});
		
  	field.reset_code_main =  	{ va(prefix.."_int", 0) };
63
	  field.write_code = 				{ va(prefix.."_int", vi("wrdata_reg", field.offset))};
64
	  field.read_code = 				{ va(vi("rddata_reg", field.offset), 0) };
twlostow's avatar
twlostow committed
65 66 67 68 69 70 71 72 73 74
	  field.ackgen_code = 			{ va(prefix.."_int", 0) };

  else
-- WB-asynchronous monostable port (bus write-only)	
 		field.signals = 					{	signal(BIT, 0, prefix.."_int"), 
 																signal(BIT, 0, prefix.."_int_delay"), 
																signal(BIT, 0, prefix.."_sync0"), 
																signal(BIT, 0, prefix.."_sync1"),
																signal(BIT, 0, prefix.."_sync2") };
					
75 76 77
	  field.ports = 						{	port(BIT, 0, "out", prefix.."_o", 
                                     "Port for asynchronous (clock: "..field.clock..") MONOSTABLE field: '"..field.name.."' in reg: '"..reg.name.."'", 
                                     VPORT_REG ) };
twlostow's avatar
twlostow committed
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101

	  field.acklen = 						5;
	   
	  field.extra_code =				{ vsyncprocess(field.clock, "rst_n_i", {
	  														vreset (0, {
	  														 va(prefix.."_o", 0);
	  														 va(prefix.."_sync0", 0);
	  														 va(prefix.."_sync1", 0);
	  														 va(prefix.."_sync2", 0);
	  														}); 

																vposedge({
																 va(prefix.."_sync0", prefix.."_int");
																 va(prefix.."_sync1", prefix.."_sync0");
																 va(prefix.."_sync2", prefix.."_sync1");
																 va(prefix.."_o", vand(prefix.."_sync2", vnot(prefix.."_sync1")));
 																});
 																});  };
																

	  field.reset_code_main = 	{ va(prefix.."_int", 0);
	 															va(prefix.."_int_delay", 0); };
	 															

102
	  field.write_code =				{	va(prefix.."_int", vi("wrdata_reg", field.offset));
twlostow's avatar
twlostow committed
103 104
	  														va(prefix.."_int_delay", vi("wrdata_reg", field.offset)); };

105
	  field.read_code =					{ va(vi("rddata_reg", field.offset), 0)};
twlostow's avatar
twlostow committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

	  field.ackgen_code_pre =		{ va(prefix.."_int", prefix.."_int_delay");
	  														va(prefix.."_int_delay", 0); };
  end
end


-- generates code for BIT-type field
function gen_hdl_code_bit(field, reg)
	local prefix = gen_hdl_field_prefix(field, reg); 

  field.prefix = prefix;

-- BIT-type field using WB bus clock
  if(field.clock == nil) then
    if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) bitfield
123
			field.ports =						{ port(BIT, 0, "out", prefix.."_o", "Port for BIT field: '"..field.name.."' in reg: '"..reg.name.."'", VPORT_REG ) };
twlostow's avatar
twlostow committed
124 125 126
			field.signals = 				{ signal(BIT, 0, prefix.."_int") };
			field.acklen = 					1;
			
127
			field.write_code =			{ --va(vi("rddata_reg", field.offset), vundefined()),
128
																va(prefix.."_int",  vi("wrdata_reg", field.offset)) };
twlostow's avatar
twlostow committed
129
			field.read_code = 			{ va(vi("rddata_reg", field.offset), prefix.."_int") };
130
	    field.reset_code_main =	{ va(prefix.."_int", csel(field.reset_value == nil, 0, field.reset_value)) };
twlostow's avatar
twlostow committed
131 132 133 134
			field.extra_code =			{ va(prefix.."_o", prefix.."_int") };

	  elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(read-only) bitfield
135
	   	field.ports =						{ port(BIT, 0, "in", prefix.."_i", "Port for BIT field: '"..field.name.."' in reg: '"..reg.name.."'", VPORT_REG) };
twlostow's avatar
twlostow committed
136 137
			field.signals = 				{  };
			field.acklen = 					1;
138
			field.write_code =			{ }; --va(vi("rddata_reg", field.offset), vundefined()) };
twlostow's avatar
twlostow committed
139 140 141 142 143 144 145 146 147 148 149 150 151
			field.read_code = 			{ va(vi("rddata_reg", field.offset), prefix.."_i") };
      field.reset_code_main =	{  };
			field.extra_code =	{  };

	  elseif (field.access == ACC_WO_RO) then
-- bus(write-only), dev(read-only) bitfield - unsupported yet (use RW/RO type instead)
			die("WO-RO type unsupported yet ("..field.name..")");

	  elseif (field.access == ACC_RW_RW) then
-- dual-write bitfield (both from the bus and the device)
			if(field.load == LOAD_EXT) then

-- external load type (e.g. the register itself is placed outside the WB slave, which only outputs new value and asserts the "load" signal for single clock cycle upon bus write.
152 153 154
		    field.ports =						{	port(BIT, 0, "out", prefix.."_o", "Ports for BIT field: '"..field.name.."' in reg: '"..reg.name.."'", VPORT_REG),
							  									port(BIT, 0, "in", prefix.."_i", nil, VPORT_REG),	    
																	port(BIT, 0, "out", prefix.."_load_o", nil, VPORT_REG) };	    
twlostow's avatar
twlostow committed
155 156 157 158
	
		    field.acklen =			 		1;
		    
		    field.read_code = 			{ va(vi("rddata_reg", field.offset), prefix.."_i") };
159
		    field.write_code = 			{ --va(vi("rddata_reg", field.offset), vundefined()),
160
															    va(prefix.."_load_o", 1) };
twlostow's avatar
twlostow committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174
		    field.extra_code =			{ va(prefix.."_o", vi("wrdata_reg", field.offset)) };
		    field.ackgen_code_pre = { va(prefix.."_load_o", 0) };
		    field.ackgen_code  = 		{ va(prefix.."_load_o", 0) };
		    field.reset_code_main = { va(prefix.."_load_o", 0) };
	
			else
		    die("internal RW/RW register storage unsupported yet ("..field.name..")");
			end
    end
	else
-- asynchronous bit-type register

    if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) bitfield, asynchronous
175
			field.ports =						{ port(BIT, 0, "out", prefix.."_o", "Port for asynchronous (clock: "..field.clock..") BIT field: '"..field.name.."' in reg: '"..reg.name.."'", VPORT_REG) };
twlostow's avatar
twlostow committed
176 177 178 179 180
			field.signals = 				{ signal(BIT, 0, prefix.."_int"),
												  			signal(BIT, 0, prefix.."_sync0"),
												  			signal(BIT, 0, prefix.."_sync1") };
					
			field.acklen = 					4;
181 182
			field.write_code =			{ va(prefix.."_int", vi("wrdata_reg", field.offset)) };
																--va(vi("rddata_reg", field.offset), vundefined()) };
twlostow's avatar
twlostow committed
183 184
			field.read_code = 			{ va(vi("rddata_reg", field.offset), prefix.."_int") };

185
	    field.reset_code_main =	{ va(prefix.."_int", csel(field.reset_value == nil, 0, field.reset_value)) };
twlostow's avatar
twlostow committed
186

187
			field.extra_code =			{	vcomment("synchronizer chain for field : "..field.name.." (type RW/RO, clk_sys_i <-> "..field.clock..")");
twlostow's avatar
twlostow committed
188 189
																vsyncprocess(field.clock, "rst_n_i", {
																vreset(0, {
190 191 192
 								    							va(prefix.."_o", csel(field.reset_value == nil, 0, field.reset_value));
 							    								va(prefix.."_sync0", csel(field.reset_value == nil, 0, field.reset_value));
																	va(prefix.."_sync1", csel(field.reset_value == nil, 0, field.reset_value));
twlostow's avatar
twlostow committed
193 194 195 196 197 198 199 200 201 202 203 204
																});
																vposedge({
																	va(prefix.."_sync0", prefix.."_int");
																	va(prefix.."_sync1", prefix.."_sync0");
																	va(prefix.."_o", prefix.."_sync1");
																});
																});
															 };

		elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(write-only) bitfield, asynchronous

205
		field.ports =							{ port(BIT, 0, "in", prefix.."_i", "Port for asynchronous (clock: "..field.clock..") BIT field: '"..field.name.."' in reg: '"..reg.name.."'", VPORT_REG) };
twlostow's avatar
twlostow committed
206 207 208 209
		field.signals = 					{ signal(BIT, 0, prefix.."_sync0"),
															  signal(BIT, 0, prefix.."_sync1") };
					
		field.acklen = 						1;
210
		field.write_code =				{ };--va(vi("rddata_reg", field.offset), vundefined()) };
twlostow's avatar
twlostow committed
211 212 213 214
		field.read_code = 				{ va(vi("rddata_reg", field.offset), prefix.."_sync1") };

    field.reset_code_main =		{ };

215
		field.extra_code =				{	vcomment("synchronizer chain for field : "..field.name.." (type RO/WO, "..field.clock.." -> clk_sys_i)");
twlostow's avatar
twlostow committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
																vsyncprocess(field.clock, "rst_n_i", {
																vreset(0, {
																va(prefix.."_sync0", 0); 
																va(prefix.."_sync1", 0);
																});
																
																vposedge({
																va(prefix.."_sync0", prefix.."_i");
																va(prefix.."_sync1", prefix.."_sync0");
																});
																});
															};

    elseif (field.access == ACC_RW_RW) then
-- asynchronous dual-write bitfield. Tough shit :/

		if(field.load ~= LOAD_EXT) then
		    die("Only external load is supported for RW/RW bit fields");
			end

			local comment = "Ports for asynchronous (clock: "..field.clock..") RW/RW BIT field: '"..field.name.."' in reg: '"..reg.name.."'";

238 239 240
   		field.ports =									{	port(BIT, 0, "out", prefix.."_o", comment, VPORT_REG),
																			port(BIT, 0, "in", 	prefix.."_i", nil, VPORT_REG),
																			port(BIT, 0, "out", prefix.."_load_o", nil, VPORT_REG) };  
twlostow's avatar
twlostow committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254


			field.signals = 							{ signal(BIT, 0, prefix.."_int_read"),
																			signal(BIT, 0, prefix.."_int_write"),
																			signal(BIT, 0, prefix.."_lw"),
																			signal(BIT, 0, prefix.."_lw_delay"),
																			signal(BIT, 0, prefix.."_lw_read_in_progress"),
																			signal(BIT, 0, prefix.."_lw_s0"),
																			signal(BIT, 0, prefix.."_lw_s1"),
																			signal(BIT, 0, prefix.."_lw_s2"),
																			signal(BIT, 0, prefix.."_rwsel") };
																			
			field.acklen = 									6;
		
255
			field.write_code =						{ --va(vi("rddata_reg", field.offset), vundefined());
256
																			va(prefix.."_int_write", vi("wrdata_reg", field.offset));
twlostow's avatar
twlostow committed
257 258 259 260 261
																			va(prefix.."_lw", 1);
																			va(prefix.."_lw_delay", 1);
																			va(prefix.."_lw_read_in_progress", 0);
																			va(prefix.."_rwsel", 1); }; 

262 263 264 265 266 267
			field.read_code =						{ 	vif(vequal("wb_we_i", 0), {
																				va(vi("rddata_reg", field.offset), vundefined());
																				va(prefix.."_lw", 1);
																				va(prefix.."_lw_delay", 1);
																				va(prefix.."_lw_read_in_progress", 1);
																				va(prefix.."_rwsel", 0); }  ); };
twlostow's avatar
twlostow committed
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
																			

			field.reset_code_main =				{ va(prefix.."_lw", 0);
																			va(prefix.."_lw_delay", 0);
																			va(prefix.."_lw_read_in_progress", 0);
																			va(prefix.."_rwsel", 0);
																			va(prefix.."_int_write", 0);
																		};
							

			field.ackgen_code_pre =				{ va(prefix.."_lw", prefix.."_lw_delay");
																			va(prefix.."_lw_delay", 0);
																			vif(vand(vequal(vi("ack_sreg", 1), 1), vequal(prefix.."_lw_read_in_progress", 1)), {
																				va(vi("rddata_reg", field.offset), prefix.."_int_read");
																				va(prefix.."_lw_read_in_progress", 0);
																			});
																		};


287
			field.extra_code =						{ vcomment("asynchronous BIT register : "..field.name.." (type RW/WO, "..field.clock.." <-> clk_sys_i)");
twlostow's avatar
twlostow committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
											    					  vsyncprocess(field.clock, "rst_n_i", {
																				vreset(0, {
															 					  va(prefix.."_lw_s0", 0); 
																					va(prefix.."_lw_s1", 0); 
																					va(prefix.."_lw_s2", 0); 
																					va(prefix.."_int_read", 0); 
																					va(prefix.."_load_o", 0); 
																					va(prefix.."_o", 0);
																				});
																	      vposedge({
																					va(prefix.."_lw_s0", prefix.."_lw");
																					va(prefix.."_lw_s1", prefix.."_lw_s0");
																					va(prefix.."_lw_s2", prefix.."_lw_s1");
																					vif(vand(vequal(prefix.."_lw_s2", 0), vequal(prefix.."_lw_s1", 1)), {
																						vif(vequal(prefix.."_rwsel", 1), {
																							va(prefix.."_o", prefix.."_int_write");
																							va(prefix.."_load_o", 1);
																						}, {
																							va(prefix.."_load_o", 0);
																							va(prefix.."_int_read", prefix.."_i");
																						});
																					}, {
																						va(prefix.."_load_o", 0);
																					});
																					});
																					});
																				};

		elseif (field.access == ACC_WO_RO) then
			die("WO-RO type unsupported yet ("..field.name..")");
    end
	end
end

-- generates the bit-range for accessing a certain register field from WB-bus
function vir(name, field)
	local syn = {};
	syn.t="index";
	syn.name=name;
	syn.h=field.offset+field.size-1;
	syn.l=field.offset;
	return syn;
end

-- generates code for slv, signed or unsigned fields
function gen_hdl_code_slv(field, reg)
	local prefix = gen_hdl_field_prefix(field, reg); 


  field.prefix = prefix;

-- synchronous signed/unsigned/slv field
  if(field.clock == nil) then
  
	  if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) slv
344
			field.ports =						{ port(field.type, field.size, "out", prefix.."_o", "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'", VPORT_REG) };
twlostow's avatar
twlostow committed
345 346 347 348
			field.signals = 				{ signal(SLV, field.size, prefix.."_int") };
			field.acklen = 					1;
			field.write_code =			{ va(prefix.."_int", vir("wrdata_reg", field)); };
			field.read_code = 			{ va(vir("rddata_reg", field), prefix.."_int"); };
349
	    field.reset_code_main =	{ va(prefix.."_int",  csel(field.reset_value == nil, 0, field.reset_value)); };
twlostow's avatar
twlostow committed
350 351 352 353
			field.extra_code =			{ va(prefix.."_o", prefix.."_int"); };
		
    elseif (field.access == ACC_RO_WO) then
-- bus(read-only), dev(write-only) slv
354
			field.ports =						{ port(field.type, field.size, "in", prefix.."_i",  "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'", VPORT_REG) };
twlostow's avatar
twlostow committed
355 356 357 358 359 360 361 362 363 364 365 366 367
			field.signals = 				{  };
			field.acklen = 					1;
			field.write_code =			{  };
			field.read_code = 			{ va(vir("rddata_reg", field), prefix.."_i"); };
   		field.reset_code_main =	{  };
			field.extra_code =			{  };

	  elseif (field.access == ACC_RW_RW) then
-- bus(read-write), dev(read-write) slv
   		if(field.load ~= LOAD_EXT) then
		    die("Only external load is supported for RW/RW slv/signed/unsigned fields");
			end

368 369 370
		    field.ports =						{	port(field.type, field.size, "out", prefix.."_o",  "Port for "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'", VPORT_REG),
										    					port(field.type, field.size, "in", prefix.."_i", nil, VPORT_REG),	    
																	port(BIT, 0, "out", prefix.."_load_o", nil, VPORT_REG) };	    
twlostow's avatar
twlostow committed
371 372 373 374
	
		    field.acklen = 					1;
		    
		    field.read_code = 			{ va(vir("rddata_reg", field), prefix.."_i"); };
375
		    field.write_code = 			{ va(prefix.."_load_o", 1); };
twlostow's avatar
twlostow committed
376 377 378 379
		    field.extra_code =			{ va(prefix.."_o", vir("wrdata_reg", field)); };
		    field.ackgen_code_pre = { va(prefix.."_load_o", 0);};
		    field.ackgen_code = 		{ va(prefix.."_load_o", 0); };
		    field.reset_code_main = { va(prefix.."_load_o", 0); };
380 381 382 383

		elseif (field.access == ACC_WO_RO) then
			 die("WO-RO type unsupported yet ("..field.name..")");

twlostow's avatar
twlostow committed
384 385 386 387 388 389 390 391
		end
	else
-- asynchronous register. Even tougher shit :(

		if(field.access == ACC_RW_RO) then
-- bus(read-write), dev(read-only) slv/signed/unsigned
			local comment = "Port for asynchronous (clock: "..field.clock..") "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'";

392
			field.ports =									{ port(field.type, field.size, "out", prefix.."_o", comment, VPORT_REG) };
twlostow's avatar
twlostow committed
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408

			field.signals = 							{ signal(SLV, field.size, prefix.."_int"),
																			signal(BIT, 0, prefix.."_swb"),
																			signal(BIT, 0, prefix.."_swb_delay"),
																			signal(BIT, 0, prefix.."_swb_s0"),
																			signal(BIT, 0, prefix.."_swb_s1"),
																			signal(BIT, 0, prefix.."_swb_s2") };
							
			field.acklen = 								4;
		
			field.write_code =						{ va(prefix.."_int", vir("wrdata_reg", field));
																			va(prefix.."_swb", 1);
																			va(prefix.."_swb_delay", 1); };
							
			field.read_code = 						{ va(vir("rddata_reg", field), prefix.."_int"); };
		
409
			field.reset_code_main =				{ va(prefix.."_int", csel(field.reset_value == nil, 0, field.reset_value)); 
twlostow's avatar
twlostow committed
410 411 412 413 414 415 416
																			va(prefix.."_swb", 0);
																			va(prefix.."_swb_delay", 0); };
										
			field.ackgen_code_pre =				{ va(prefix.."_swb", prefix.."_swb_delay");
																			va(prefix.."_swb_delay", 0); };
			

417
			field.extra_code =						{ vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/RO, "..field.clock.." <-> clk_sys_i)");
twlostow's avatar
twlostow committed
418 419 420 421 422
																			vsyncprocess(field.clock, "rst_n_i", {
																				vreset(0, {
																					va(prefix.."_swb_s0", 0);
																					va(prefix.."_swb_s1", 0); 
																					va(prefix.."_swb_s2", 0); 
423
																					va(prefix.."_o", csel(field.reset_value == nil, 0, field.reset_value));
twlostow's avatar
twlostow committed
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
																				});
																				vposedge({
																					va(prefix.."_swb_s0", prefix.."_swb");
																					va(prefix.."_swb_s1", prefix.."_swb_s0");
																					va(prefix.."_swb_s2", prefix.."_swb_s1");
																					vif(vand(vequal(prefix.."_swb_s2", 0), vequal(prefix.."_swb_s1", 1)), {
																						va(prefix.."_o", prefix.."_int");
																					});
																				});
																			});
																			};
																		
		elseif(field.access == ACC_RO_WO) then
-- bus(read-write), dev(read-only) slv
			local comment = "Port for asynchronous (clock: "..field.clock..") "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'";
	
440
			field.ports =									{ port(field.type, field.size, "in", prefix.."_i", comment, VPORT_REG) };
twlostow's avatar
twlostow committed
441 442 443 444 445 446 447 448 449 450 451 452

			field.signals = 							{ signal(SLV, field.size, prefix.."_int"),
																			signal(BIT, 0, prefix.."_lwb"),
																			signal(BIT, 0, prefix.."_lwb_delay"),
																			signal(BIT, 0, prefix.."_lwb_in_progress"),
																			signal(BIT, 0, prefix.."_lwb_s0"),
																			signal(BIT, 0, prefix.."_lwb_s1"),
																			signal(BIT, 0, prefix.."_lwb_s2") };
					  
			field.acklen = 								6;
			field.write_code =						{  }; 

453 454 455 456
			field.read_code = 						{ vif(vequal("wb_we_i", 0), {
																				va(prefix.."_lwb", 1);
																				va(prefix.."_lwb_delay", 1);
																				va(prefix.."_lwb_in_progress", 1); } ); };
twlostow's avatar
twlostow committed
457 458 459 460 461 462 463 464 465 466 467 468 469 470

			field.reset_code_main =				{ va(prefix.."_lwb", 0);
																			va(prefix.."_lwb_delay", 0);
																			va(prefix.."_lwb_in_progress", 0); };


			field.ackgen_code_pre =				{ va(prefix.."_lwb", prefix.."_lwb_delay");
																			va(prefix.."_lwb_delay", 0);
																			vif(vand(vequal(vi("ack_sreg", 1), 1), vequal(prefix.."_lwb_in_progress", 1)), {
																				va(vir("rddata_reg", field), prefix.."_int");
																				va(prefix.."_lwb_in_progress", 0);
																			});
																		};

471
			field.extra_code =						{ vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RO/WO, "..field.clock.." <-> clk_sys_i)"),
twlostow's avatar
twlostow committed
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
																			vsyncprocess(field.clock, "rst_n_i", {
																			vreset(0, { 
																				va(prefix.."_lwb_s0", 0);
																				va(prefix.."_lwb_s1", 0);
																				va(prefix.."_lwb_s2", 0); 
																				va(prefix.."_int", 0);
																			});
																			vposedge({
																				va(prefix.."_lwb_s0", prefix.."_lwb");
																				va(prefix.."_lwb_s1", prefix.."_lwb_s0");
																				va(prefix.."_lwb_s2", prefix.."_lwb_s1");
																				vif(vand(vequal(prefix.."_lwb_s1", 1), vequal(prefix.."_lwb_s2", 0)), {
																					va(prefix.."_int", prefix.."_i");
																				});
																			});
																		});																			
																		};
	
		elseif(field.access == ACC_RW_RW) then
-- async bus(read-write), dev(read-write) slv. gooosh...

   		if(field.load ~= LOAD_EXT) then
		    die("Only external load is supported for RW/RW slv/signed/unsigned fields");
			end

			local comment = "Ports for asynchronous (clock: "..field.clock..") "..fieldtype_2_vhdl[field.type].." field: '"..field.name.."' in reg: '"..reg.name.."'";

499 500 501
   		field.ports =									{	port(field.type, field.size, "out", prefix.."_o", comment, VPORT_REG),
																			port(field.type, field.size, "in", prefix.."_i", nil, VPORT_REG),
																			port(BIT, 0, "out", prefix.."_load_o", nil, VPORT_REG) };  
twlostow's avatar
twlostow committed
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522


			field.signals = 							{ signal(SLV, field.size, prefix.."_int_read"),
																			signal(SLV, field.size, prefix.."_int_write"),
																			signal(BIT, 0, prefix.."_lw"),
																			signal(BIT, 0, prefix.."_lw_delay"),
																			signal(BIT, 0, prefix.."_lw_read_in_progress"),
																			signal(BIT, 0, prefix.."_lw_s0"),
																			signal(BIT, 0, prefix.."_lw_s1"),
																			signal(BIT, 0, prefix.."_lw_s2"),
																			signal(BIT, 0, prefix.."_rwsel") };
																			
							
			field.acklen = 									6;
		
			field.write_code =						{ va(prefix.."_int_write", vir("wrdata_reg", field));
																			va(prefix.."_lw", 1);
																			va(prefix.."_lw_delay", 1);
																			va(prefix.."_lw_read_in_progress", 0);
																			va(prefix.."_rwsel", 1); }; 

523 524 525 526 527 528
			field.read_code =						{ 	vif(vequal("wb_we_i", 0), { 
																				va(prefix.."_lw", 1);
																				va(prefix.."_lw_delay", 1);
																				va(prefix.."_lw_read_in_progress", 1);
																				va(prefix.."_rwsel", 0); } );
																			};
twlostow's avatar
twlostow committed
529 530 531 532 533 534 535 536 537 538 539 540 541 542
																			

			field.reset_code_main =				{ va(prefix.."_lw", 0);
																			va(prefix.."_lw_delay", 0);
																			va(prefix.."_lw_read_in_progress", 0);
																			va(prefix.."_rwsel", 0);
																			va(prefix.."_int_write", 0);
																		};
							

			field.ackgen_code_pre =				{ va(prefix.."_lw", prefix.."_lw_delay");
																			va(prefix.."_lw_delay", 0);
																			vif (vand(vequal(vi("ack_sreg", 1), 1), vequal(prefix.."_lw_read_in_progress", 1)), {
																				va(vir("rddata_reg", field), prefix.."_int_read");
twlostow's avatar
twlostow committed
543
																				va(prefix.."_lw_read_in_progress", 0);
twlostow's avatar
twlostow committed
544 545 546
																			});
																			};

547
			field.extra_code =						{ vcomment("asynchronous "..fieldtype_2_vhdl[field.type].." register : "..field.name.." (type RW/WO, "..field.clock.." <-> clk_sys_i)");
twlostow's avatar
twlostow committed
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
											    					  vsyncprocess(field.clock, "rst_n_i", {
													 					  vreset(0, {
																				va(prefix.."_lw_s0", 0);
																				va(prefix.."_lw_s1", 0);
																				va(prefix.."_lw_s2", 0);
																				va(prefix.."_o", 0); 
																				va(prefix.."_load_o", 0); 
	 																			va(prefix.."_int_read", 0);
																			});
																			vposedge({	
																				va(prefix.."_lw_s0", prefix.."_lw");
																				va(prefix.."_lw_s1", prefix.."_lw_s0");
																				va(prefix.."_lw_s2", prefix.."_lw_s1");
																				vif(vand(vequal(prefix.."_lw_s2", 0), vequal(prefix.."_lw_s1", 1)), {
																					vif(vequal(prefix.."_rwsel", 1), {
																						va(prefix.."_o", prefix.."_int_write");
																						va(prefix.."_load_o", 1);
																					}, {
																						va(prefix.."_load_o", 0);
																						va(prefix.."_int_read", prefix.."_i");
																					});
																				}, {
																					va(prefix.."_load_o", 0);
																				});
																			});
																			});
																			};
		end 
	end
end

function gen_hdl_code_passthrough(field, reg)
	local prefix = gen_hdl_field_prefix(field, reg); 

	if(field.clock == nil) then
-- sync pass-through

			local comment = "Ports for PASS_THROUGH field: '"..field.name.."' in reg: '"..reg.name.."'";

587 588
   		field.ports =									{	port(SLV, field.size, "out", prefix.."_o", comment, VPORT_REG),
   																		port(BIT, 0, "out", prefix.."_wr_o", nil, VPORT_REG) };
twlostow's avatar
twlostow committed
589 590 591 592 593 594 595 596 597 598 599 600 601 602

			field.acklen = 1;
			
			field.reset_code_main	= 			{ va(prefix.."_wr_o", 0); };
			field.read_code = 						{};
			field.write_code = 						{ va(prefix.."_wr_o", 1); };
			field.ackgen_code_pre =				{ va(prefix.."_wr_o", 0); };
			field.ackgen_code	 =					{ va(prefix.."_wr_o", 0); };
			field.extra_code =						{ vcomment("pass-through field: "..field.name.." in register: "..reg.name);
																			va(prefix.."_o", vir("wrdata_reg", field)); }
	else

			local comment = "Ports for asynchronous (clock: "..field.clock..") PASS_THROUGH field: '"..field.name.."' in reg: '"..reg.name.."'";

603 604
   		field.ports =									{	port(SLV, field.size, "out", prefix.."_o", comment, VPORT_REG),
   																		port(BIT, 0, "out", prefix.."_wr_o", nil, VPORT_REG) };
twlostow's avatar
twlostow committed
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642

			field.signals =								{ signal(BIT, 0, prefix.."_wr_int"), 
																			signal(BIT, 0, prefix.."_wr_int_delay"), 
																			signal(BIT, 0, prefix.."_wr_sync0"), 
																			signal(BIT, 0, prefix.."_wr_sync1"),
																			signal(BIT, 0, prefix.."_wr_sync2") };

			field.acklen = 4;
			
			field.reset_code_main	= 			{ va(prefix.."_wr_int", 0);
																			va(prefix.."_wr_int_delay", 0); };
			field.read_code = 						{};

			field.write_code = 						{ va(prefix.."_wr_int", 1); 
																			va(prefix.."_wr_int_delay", 1);  };
			field.ackgen_code_pre =				{ va(prefix.."_wr_int", prefix.."_wr_int_delay");
																			va(prefix.."_wr_int_delay", 0); };

			field.extra_code =						{ vcomment("pass-through field: "..field.name.." in register: "..reg.name);
																			va(prefix.."_o", vir("wrdata_reg", field));
																			vsyncprocess(field.clock, "rst_n_i", {
																				vreset(0, {
																					va(prefix.."_wr_sync0", 0);
																					va(prefix.."_wr_sync1", 0);
																					va(prefix.."_wr_sync2", 0);
																				});
																				vposedge({
																					va(prefix.."_wr_sync0", prefix.."_wr_int");
																					va(prefix.."_wr_sync1", prefix.."_wr_sync0");
																					va(prefix.."_wr_sync2", prefix.."_wr_sync1");
																					va(prefix.."_wr_o", vand(prefix.."_wr_sync1", vnot(prefix.."_wr_sync2")));
																				});
																			});
																			}
			end

end

643 644 645 646 647 648 649 650 651 652 653 654
function gen_hdl_code_constant(field, reg)
	local prefix = gen_hdl_field_prefix(field, reg); 

  if(field.value == nil) then
 		die("No value defined for CONSTANT field '"..field.name.."'.");
	end
	
	field.ports =		{};
	field.acklen = 1;
	field.read_code = 			{ va(vir("rddata_reg", field), field.value ); };
end

twlostow's avatar
twlostow committed
655
-- generates code which loads data unused bits of data output register with Xs 
656
function fill_unused_bits(target, reg, unused_zeroes)
twlostow's avatar
twlostow committed
657 658
	local t={};
	local code={};
659
	local all_wo = true;
twlostow's avatar
twlostow committed
660 661

	foreach_subfield(reg, function(field, reg)
662
													if(field.type == SLV or field.type == SIGNED or field.type == UNSIGNED or field.type == CONSTANT) then
twlostow's avatar
twlostow committed
663 664 665
														for i=field.offset, (field.offset+field.size-1) do t[i] = 1; end
													elseif(field.type == BIT or field.type == MONOSTABLE)  then
														t[field.offset] = 1;
666 667 668
												 end

												 if(field.access_bus ~= WRITE_ONLY) then all_wo = false; end
twlostow's avatar
twlostow committed
669 670
												end);

671 672 673 674 675
	if (unused_zeroes) then
		 unused = 0;
	else
		 unused = vundefined();
	end
676 677
	if(all_wo) then
		 for i = 0, DATA_BUS_WIDTH-1 do
678
				 table_join(code, { va(vi(target, i), unused); });
679 680 681 682
		 end
		 return code;
	end

twlostow's avatar
twlostow committed
683 684
	for i = 0, DATA_BUS_WIDTH-1 do
		if(t[i] == nil) then
685
			table_join(code, { va(vi(target, i), unused); });
twlostow's avatar
twlostow committed
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
		end
	end
	
	return code;
end


-- generates VHDL code for single register field
function gen_hdl_code_reg_field(field, reg)
  
	if(field.type == MONOSTABLE) then
    gen_hdl_code_monostable(field, reg);
	elseif(field.type == BIT) then 
    gen_hdl_code_bit(field, reg);
	elseif(field.type == SIGNED or field.type == UNSIGNED or field.type == SLV) then	    
    gen_hdl_code_slv(field, reg);
	elseif(field.type == PASS_THROUGH) then
		gen_hdl_code_passthrough(field, reg);
704 705
	elseif(field.type == CONSTANT) then
		gen_hdl_code_constant(field, reg);
twlostow's avatar
x  
twlostow committed
706 707 708 709 710 711 712 713 714 715 716 717
 end

 if(field.ack_read ~= nil) then 
		table_join(field.ports, { port (BIT, 0, "out", field.ack_read) });
		table_join(field.read_code, { va(field.ack_read, 1) });

		if(field.reset_code_main == nil) then field.reset_code_main = {}; end
		table_join(field.reset_code_main, { va(field.ack_read,  0) });

		if(field.ackgen_code == nil) then field.ackgen_code= {}; end
		table_join(field.ackgen_code, { va(field.ack_read, 0) });
 end
twlostow's avatar
twlostow committed
718 719 720 721 722 723 724 725
end

-- generates VHDL for single register
function gen_abstract_code(reg)

 	reg.full_hdl_prefix = string.lower(periph.hdl_prefix.."_"..reg.hdl_prefix);

	if(reg.no_std_regbank == true) then
twlostow's avatar
twlostow committed
726
		 dbg("reg: ",reg.name," - no std regbank");
twlostow's avatar
twlostow committed
727 728 729 730 731 732
		return;
	end


	if(reg.__type == TYPE_RAM) then
		gen_code_ram(reg);
733
 else
twlostow's avatar
twlostow committed
734 735 736 737 738 739 740 741
  	foreach_subfield(reg, function(field, reg) gen_hdl_code_reg_field(field, reg); end );
  end
end

function gen_hdl_block_select_bits()
  return vi("rwaddr_reg", address_bus_width-1, (address_bus_width - address_bus_select_bits));
end