Перейти к содержанию
    

Как правильно описать мультиплексор

Требуется мультиплексор для задачи которая в общем описана в testbench ниже. Сначала я интуитивно всё это нарисовал и всё казалось нормально (см. первый вариант).

Но потом стало ясно что ни кто так не делает. Поискал по форуму всё с "mux" (в частности). 

Написал вариант генерирующий мультиплексор (см. второй вариант).

Spoiler
module testbench();

	initial begin
		$dumpfile("mux2.vcd");
		$dumpvars(0, testbench);
		#100 $stop;
	end

	reg clk;
	initial clk = 1;
	always #5 clk = !clk;

	// некий аддер складывающий разные значения на каждом такте
	wire [7:0] a, b;
	reg [7:0] s;
	always @ (posedge clk)
		s <= a + b;

	// управляющий сигнал для мультиплексора
	reg t1, t2, t3;
	initial begin
		t1 = 1;
		t2 = 0;
		t3 = 0;
		forever @ (posedge clk) {t1, t2, t3} <= {t3, t1 ,t2};
	end

	// входы мультиплексора
	reg [7:0] i, j, k; // для a
	reg [7:0] l, m, n; // для b
	initial begin
		i = 1;
		j = 10;
		k = 100;
		l = 101;
		m = 102;
		n = 103;
	end

	mux2 uut (
		.t1 (t1),
		.t2 (t2),
		.t3 (t3),
		.i  (i ),
		.j  (j ),
		.k  (k ),
		.l  (l ),
		.m  (m ),
		.n  (n ),
		.a  (a ),
		.b  (b )
	);

endmodule



module mux2(
	input       t1,
	input       t2,
	input       t3,
	input [7:0] i,
	input [7:0] j,
	input [7:0] k,
	input [7:0] l,
	input [7:0] m,
	input [7:0] n,
	output     [7:0] a,
	output reg [7:0] b
);

	// 2 разных мультиплексора

	// первый вариант
	wire [7:0] a1,a2,a3;
	assign
		a = a1 | a2 | a3,
		a1 = t1 ? i : 0,
		a2 = t2 ? j : 0,
		a3 = t3 ? k : 0;

	// второй вариант
	always @ (*)
		case ({t1, t2, t3})
		'b100:
			b = l;
		'b010:
			b = m;
		'b001:
			b = n;
		default:
			b = 0;
		endcase

endmodule

mux2.thumb.png.711116ae5948e059ac88fdbb5843d6e5.png

С использованием for для генерации комбинаторной логики всё ясно, но тут управляющий сигнал по другому устроен. И переделывать его, вроде бы, нет оснований. Так что я case использовал.

Может будут какие-нибудь замечания...

правильно ли использовать always @ (*) ?

Изменено пользователем Вадим Н.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 hours ago, Вадим Н. said:

Может будут какие-нибудь замечания

И первый и второй варианты описания вполне рабочие и применяемые на практике,  как и вариант с  for. 
Но эти варианты  логически неэквивалентны.  И это надо учитывать при применении и анализе результатов синтеза.  

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 07.12.2022 в 07:15, Вадим Н. сказал:

Требуется мультиплексор

Может будут какие-нибудь 

 

если требуется мультиплексор, наверно его надо описывать как мультиплексор.  В документе xst.pdf можно посмотреть.

module mux_bus
#(parameter w = 4,
                n = 4,
         nclog2 = $clog2(n)
)
(
input    [w*n-1:0] in_data, 
input [nclog2-1:0] sel, 
output      [w-1:0] out_data
); 

assign out_data = in_data[sel*w +: w];

endmodule

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

litv, спасибо!

ознакомился с "HDL Chip Design..."
подход к изложению норм. Но есть нюанс.

Spoiler
// сначала было так
		case ({t1, t2, t3})
		'b100:
			b = l;
		'b010:
			b = m;
		'b001:
			b = n;
		default:
			b = 0;
		endcase
// примерчик из книги товарища Дугласа J. Смита натолкнул меня на мысль что мне ноль то и не нужен; сделал как в книжке
		case ({t1, t2, t3})
		'b100:
			b = l;
		'b010:
			b = m;
		'b001:
			b = n;
		default:
			b = l;
		endcase
// - внешне тоже самое в RTL
// такие вариации:
		case ({t1, t2})
		'b10:
			b = l;
		'b01:
			b = m;
		default:
			b = n;
		endcase
// только хуже делают: в RTL появляется уровень комбинаторной логики с t1,t2,t3

/*

	и тут вспомнил у General Coding Guidelines Chapter 13: Recommended HDL Coding Styles*
    Altera рекомендует:
    
    If the value in the invalid cases is not important, specify those cases explicitly by
	assigning the X (don’t care) logic value instead of choosing another value. This
	assignment allows your synthesis tool to perform the best area optimizations.

*/
		case ({t1, t2, t3})
		'b100:
			b = l;
		'b010:
			b = m;
		'b001:
			b = n;
		default:
			b = 'bx;
// кое-что меняется, квартус пишет что используется на один логический элемент меньше но появляются предупреждения: вход t3 вообще не нужен, какие-то преобразования типов...
// вобщем, напрашивается дальнейшая оптимизацичя:

		case ({t2, t3})
		'b00:
			b = l;
		'b01:
			b = m;
		'b10:
			b = n;
		default:
            // здесь собственно без 1 'bx - 32 разряда
			b = 1'bx;
		endcase

/*
	итого, первый вариант самый программистский и читаемый
    последний самый экономичный, рекомендуемый Квартус-стайл-гвайдом
*/

 

 

* у меня нет этой книжки целиком, есть одна глава: General Coding Guidelines Chapter 13: Recommended HDL Coding Styles
"FPGA\intel-Altera\Quartus II\Handbook\1 Design and Synthesis\qts_qii51007.pdf"

 

RobFPGA, спасибо! вас понял. Точнее, понял оп чём речь когда прочитал про классификацию мультиплексоров в этом квартус-дизайн буке (см. выше)

 

sazh, спасибо!  это SV наверное, и уровень супер эрор-пруф прогрэмин. - не. я пока пешком )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в рамках занудства -

книжка Смита написана в 1996 году, как думаете, поменялось ли что-то в этой области за почти 30 лет?

btw: [sel*w +: w] это не SV, а Verilog 2001

-------------

upd: то есть, 1) код должен быть понятным, а чем меньше букв в описании, тем понятнее; 2) для стандартного узла всегда лучше использовать стандартное описание, а не колхозить индусский код

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хороший синтезатор оптимальную логику мультиплексоров нормально сделает сам.

Например Synplify.

Придерживаться лучше рекомендаций от производителя по реализации.

Ибо в разных семействах ПЛИС есть отличия, которые могут сильно менять оптимальное решение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 hours ago, Вадим Н. said:

подход к изложению норм. Но есть нюанс.

Маленький  нюанс как раз и может испортить "бочку меда" ... или украсить "торт".  
Когда вы пишете

// сначала было так
		case ({t1, t2, t3})
		'b100:
			b = l;
		'b010:
			b = m;
		'b001:
			b = n;
		default:
			b = 0;
		endcase
// или  
		case ({t1, t2, t3})
		'b100:
			b = l;
		'b010:
			b = m;
		'b001:
			b = n;
		default:
			b = 'bx;
 

вы создаете  мукс не на 3, а на 4 входа,  каждый из которых  выбирается логикой (декодером) от  3-х переменных. 

Вариант

		case ({t1, t2, t3})
		'b100:
			b = l;
		'b010:
			b = m;
		'b001:
			b = n;
		default:
			b = l;
		endcase

 создает мукс на  3 входа но тоже с декодером от 3-х переменных на входе 
Вариант  

		case ({t2, t3})
		'b00:
			b = l;
		'b01:
			b = m;
		'b10:
			b = n;
		default:
            // здесь собственно без 1 'bx - 32 разряда
			b = 1'bx;
		endcase

Тоже  создает мукс  на 3  входа но уже с декодером от 2-х  переменных на входе.
 
Но если у вас сигналы управления уже гарантированно ohe-hot то зачем тратить доп. логику на декодер.  Есть еще  вариант описания  мукса для one-hot входов

casez ({t2,t1,t0})
  3'b??1:
      b = l;
  3'b?1?:
      b = m;
  3'b1??:
      b = n;
endcase
// или  инверсный вариант 
case (1'b1)
  t0:
      b = l;
  t1:
      b = m;
  t2:
      b = n;
endcase

Есть еще атрибуты full_case и parallel_case  которые тоже влияют на результат синтеза.
Например  вариант с (* parallel_case *) case ({t2,t1,t0}) ...  может  отличатся  по синтезу от  варианта  без этого атрибута. Так как без атрибута case синтезируется как приоритетное сравнение вариантов.     
 

Поэтому во что конкретно будет синтезироваться то или иное описание  зависит как от стиля (так как не все описания эквивалентны по логике) так и от целевой платформы, атрибутов, констрейнов и опций оптимизации.  

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 12/8/2022 at 3:16 PM, yes said:

[sel*w +: w] это не SV, а Verilog 2001

точно! Хотя "IEEE Std 1364-2001" у меня всегда под рукой, как то именно раздел "part-select" до сих пор пропускал. А всё потому что там картинок нет при столь не очевидной схеме +, -, lsb, msb %) 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 09.12.2022 в 06:48, Вадим Н. сказал:

точно! Хотя "IEEE Std 1364-2001" у меня всегда под рукой, как то именно раздел "part-select" до сих пор пропускал. А всё потому что там картинок нет при столь не очевидной схеме +, -, lsb, msb %) 

Никакого волшебства. Простой подход "железячника". Описываете полный мультиплексор. И подаете на него полный набор входных данных. Приоритетность данных оставляете для себя (если надо, меняя содержимое входного вектора). Минимизация комбинаторной логики на откуп синтезатору. И все наглядно. Как вариант для рассмотрения :

module mux_bus
(
input  [7:0] k, j, l, 
input          t3, t2, t1, 
output [7:0] o_data
); 

wire         [2:0] sel;
wire [8*8-1:0] i_data;

assign i_data = {8'd0, 8'd0, 8'd0, k, 8'd0, j, l, 8'd0},
             sel = {t3, t2, t1};

assign o_data = i_data[sel*8 +: 8];

endmodule
 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

sazh,

попробовал примерчик свой переделать в таком стиле

Spoiler
/*

	mux_hardw.v
	
	Вариант явно объявленного мультиплексора

	RTL-представление менее понятное по проводам так как есть шина данных аж 64 бит
	и шина выбора почему то 6 бит а не 3 или 2,
	но результат синтеза по ресурсам точно тот же:
	
; Total logic elements               ; 34
;     Total combinational functions  ; 34
;     Dedicated logic registers      ; 0
; Total registers                    ; 0
; Total pins                         ; 67


*/

module testbench();

	initial begin
		$dumpfile("mux_hardw.vcd");
		$dumpvars(0, testbench);
		#100 $stop;
	end

	reg clk;
	initial clk = 1;
	always #5 clk = !clk;

	// некий аддер складывающий разные значения на каждом такте
	wire [7:0] a, b;
	reg [7:0] s;
	always @ (posedge clk)
		s <= a + b;

	// управляющий сигнал для мультиплексора
	reg t1, t2, t3;
	initial begin
		t1 = 1;
		t2 = 0;
		t3 = 0;
		forever @ (posedge clk) {t1, t2, t3} <= {t3, t1 ,t2};
	end

	// входы мультиплексора
	reg [7:0] i, j, k; // для a
	reg [7:0] l, m, n; // для b
	initial begin
		i = 'd1;
		j = 'd10;
		k = 'd100;
		l = 'd101;
		m = 'd102;
		n = 'd103;
	end

	mux_hardw muxhw (
		.t1 (t1),
		.t2 (t2),
		.t3 (t3),
		.i  (i ),
		.j  (j ),
		.k  (k ),
		.l  (l ),
		.m  (m ),
		.n  (n ),
		.a  (a ),
		.b  (b )
	);

endmodule



module mux_hardw (
	input       t1,
	input       t2,
	input       t3,
	input [7:0] i,
	input [7:0] j,
	input [7:0] k,
	input [7:0] l,
	input [7:0] m,
	input [7:0] n,
	output [7:0] a,
	output [7:0] b
);

	mux_bas uut (
		.t1     (t1),
		.t2     (t2),
		.t3     (t3),
		.i0     (i ),
		.i1     (j ),
		.i2     (k ),
		.o_data (a )
	);

	mux_bas same_thingy (
		.t1     (t1),
		.t2     (t2),
		.t3     (t3),
		.i0     (l ),
		.i1     (m ),
		.i2     (n ),
		.o_data (b )
	);
	
endmodule




module mux_bas (
	input        t1, t2, t3,
	input  [7:0] i0, i1, i2,
	output [7:0] o_data
); 

	wire [2:0]     sel;
	wire [8*8-1:0] i_data;

	assign
		i_data = {8'd0, 8'd0, 8'd0, i2, 8'd0, i1, i0, 8'd0},
		sel    = {t3, t2, t1};

	assign o_data = i_data[sel*8 +: 8]; // see 4.2.1 Vector bit-select and part-select addressing @ IEEE Standard Verilog 2001

endmodule

 

в принципе, норм. Спасибо! А то я как то из тех примеров что в интернете встречал не понял как оставаясь в режиме one-hot, организовать выбор адреса. Расширить шину данных до соответствия трёхбитным адресам - мне эта идея вообще не пришла. Да я сейчас ещё не уверен что это практично может быть. Ну будет в арсенале там посмотрим.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 hours ago, Вадим Н. said:

А то я как то из тех примеров что в интернете встречал не понял как оставаясь в режиме one-hot, организовать выбор адреса

Как только вы объединяете  ohe-hot в шину адреса  вы тут же теряете преимущества ohe-hot добавляя слой логики  для повторного декодирования этого адреса. 
Пару вариантов как описать  мукс  с использованием сигналов ohe-hot я приводил  выше.   

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 13.12.2022 в 07:06, Вадим Н. сказал:

Расширить шину данных до соответствия трёхбитным адресам - мне эта идея вообще не пришла. Да я сейчас ещё не уверен что это практично может быть. Ну будет в арсенале там посмотрим.

Если б работали в графическом редакторе. то пришла б.

А вообще, с case надо быть осторожным (чтоб на защелки при описании не напороться). По идее, если не напрягает приоритетное мультиплексирование:

assign o_data = t1 ? l :
                     t2 ? j :
                     t3 ? k : 8'h00;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...