А чтобы реально разобраться в тексте, советуем взять на заметку такие сайты:
10 интересных новостных IT сайтов, которые стоит добавить в закладки
А чтобы реально разобраться в тексте, советуем взять на заметку такие сайты:
User
Не влезай. Убьет! (с)
Потребность делать железо периодически возникает у многих технарей. Иногда задача позволяет нафигачить всё проводами на макетке, а иногда, к сожалению, нужно нечто посерьёзнее. Вот и меня однажды настигла потребность делать печатные платы… Лазерно-утюжная технология кустарного изготовления плат по началу сильно отталкивает своей рандомностью (на чём печатать, как греть, с какой силой давить, как отдирать, и т.д.), но друзья поделились опытом, и оказалось, что это действительно не так уж сложно. ЛУТ бесспорно дешевле любого другого варианта, и (внезапно) вполне подходит для двухслойных плат.
Кому интересно посложнее, подороже и поточнее, можно делать фоторезистом, но наша методика (основным элементом которой является особая бумага) позволяет стабильно прорабатывать шины 0.3/0.3 мм, так что в нашем сообществе бытует мнение что тян фоторезисты не нужны.
Кто не видит смысла в кустарном производстве плат, скорее всего сможет вспомнить пару случаев, когда приходилось пилить дорожки и припаивать проводки на целой партии плат. А сделав одну плату дома, можно её хорошенько отладить и приобрести уверенность в фабричных платах.
Под катом я поделюсь детерминированной методикой изготовления двухслойных печатных плат по технологии ЛУТ с различными резервными схемами на случай косяков. От идеи до включения. Будем работать с KiCad, Inkscape, наждачкой, утюгом, персульфатом аммония и гравёром.
Админ — это главный человек в компании!
$var
и подстановки команд вроде $(cmd)
подвергаются расщеплению слов, когда внутренняя строка расширяется в массив из-за расщепления в специальной переменной $IFS
с пробелом по умолчанию. Это обычно незаметно, потому что чаще всего результатом становится массив из 1 элемента, неотличимый от ожидаемой строки.Часть I
Часть II
Часть III
Часть IV
Спроектируем Little Man Computer на языке Verilog.
Статья про LMC была на Хабре.
Online симулятор этого компьютера здесь.
Напишем модуль оперативной памяти RAM/ОЗУ, состоящий из четырех (N=2) четырёхбитных (M=4) слов. Данные загружаются в ОЗУ из data_in по адресу adr при нажатии на кнопку:
module R0 #(parameter N = 2, M = 4)
(
input RAM_button, //кнопка
input [N-1:0] adr, //адрес
input [M-1:0] data_in, //порт ввода данных
output [M-1:0] RAM_out //порт вывода данных
);
reg [M-1:0] mem [2**N-1:0]; //объявляем массив mem
always @(posedge RAM_button) //при нажатии на кнопку
mem [adr] <= data_in; //загружаем данные в ОЗУ из data_in
assign RAM_out = mem[adr]; //назначаем RAM_out портом вывода данных
endmodule
```<cut/>
В качестве внешнего генератора подключим КМОП <b>таймер 555</b> (работающий от 3.3V).
Подключим <b>таймер 555</b> к счётчику, подключим счётчик к адресному входу <b>ОЗУ</b>:
```verilog
module R1 #(parameter N = 2, M = 4)
(
input timer555, RAM_button,
//input [N-1:0] adr,
input [M-1:0] data_in,
output [M-1:0] RAM_out
);
reg [1:0]counter; //объявляем счётчик
always @(posedge timer555) //при поступлении тактового сигнала
counter <= counter + 1; // счетчик увеличивается на 1
wire [N-1:0] adr;
assign adr = counter; // подключаем счётчик на адресный вход ОЗУ
reg [M-1:0] mem [2**N-1:0];
always @(posedge RAM_button)
mem [adr] <= data_in;
assign RAM_out = mem[adr];
endmodule
Здесь при описании счетчика counter и памяти mem используются неблокирующие присвоения <= Операторы присвоения рассматриваются на сайте marsohod.org здесь
Описание работы счетчика есть на сайте marsohod.org здесь
Добавим в счетчик функцию загрузки.
Загрузка осуществляется командой Counter_load:
//input Counter_load;
wire [3:0] branch_adr; // адрес перехода
assign branch_adr = data_in;
always @(posedge timer555)
begin
if(Counter_load) //по команде "Counter_load" переходим по адресу "branch_adr"
counter <= branch_adr;
else
counter <= counter + 1;
end
В отдельном модуле создаем 4bit'ный регистр (аккумулятор):
module register4
(
input [3:0] reg_data,
input reg_button,
output reg [3:0] q
);
always @(posedge reg_button)
q <= reg_data;
endmodule
Добавим в общую схему аккумулятор Acc, мультиплексор MUX2 и сумматор sum.
Сумматор прибавляет к числу в аккумуляторе Acc числа из памяти.
На сигнальные входы мультиплексора подаются числа data_in и sum.
Далее число из мультиплексора MUX2 загружается в аккумулятор Acc:
module R2 #(parameter ADDR_WIDTH = 2, DATA_WIDTH = 4)
(
input timer555, Counter_load, RAM_button,
input MUX_switch,
input Acc_button,
input [3:0] data_in,
output [3:0] Acc,
output [DATA_WIDTH-1:0] RAM,
output reg [1:0] counter
);
wire [1:0] branch_adr;
assign branch_adr = data_in[1:0];
//Counter
always @(posedge timer555)
begin
if(Counter_load)
counter <= branch_adr;
else
counter <= counter + 1;
end
wire [ADDR_WIDTH-1:0] adr;
assign adr = counter;
//RAM
reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0];
always @(posedge RAM_button)
mem [adr] <= Acc;
assign RAM = mem[adr];
//sum
wire [3:0] sum;
assign sum = Acc + RAM;
//MUX
reg [3:0] MUX2;
always @* // Always @* — значит «всегда»
MUX2 = MUX_switch ? sum : data_in;
//Accumulator
register4 Acc_reg(
.reg_data(MUX2),
.reg_button(Acc_button),
.q(Acc)
);
endmodule
Always @ — значит «всегда». Некоторые синтезаторы не понимают эту конструкцию. Мультиплексор можно написать и без Always @ (тут используется просто для примера).
Для того, чтобы произвести вычитание, надо представить вычитаемое число в дополнительном коде. Про сложение и вычитание двоичных чисел можно прочитать в учебнике "Цифорвая схемотехника и архитектура компьютера" (Дэвид М. Харрис и Сара Л. Харрис) в главе 1.4.6 Знак двоичных чисел
Добавим в основной модуль элемент, вычитающий из числа в аккумуляторе числа, хранящиеся в памяти:
wire [3:0] subtract;
assign subract = Acc - RAM ;
Заменим 2-входовой мультиплексор 4-входовым:
always @*
MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM : subtract)
: (MUX_switch[0] ? sum : data_in);
Подключим к аккумулятору устройство вывода (4bit'ный регистр), также подключим к аккумулятору 2 флага:
Флаг "Ноль" — это лог. элемент 4ИЛИ-НЕ. Флаг поднимается, если содержимое Асс равно нулю.
Флаг "Ноль или Положительное число" — это лог. элемент НЕ на старшем разряде 4-разрядного аккумулятора. Флаг поднимается, если содержимое Асс больше или равно нулю.
//флаг "Ноль"
output Z_flag;
assign Z_flag = ~(|Acc); // 4-входовой вентиль ИЛИ-НЕ
//флаг "Ноль или Положительное число"
output PZ_flag;
assign PZ_flag = ~Acc[3];
Здесь мы описали многовходовой вентиль ИЛИ-НЕ как ~(|Acc)
Также в языке Verilog поддерживается набор типов логических вентилей (Gate Types).
Для логических вентилей определены ключевые слова: and (И), nand (И-НЕ), or (ИЛИ), nor (ИЛИ-НЕ), xor (Исключающее ИЛИ), xnor (Исключающее ИЛИ-НЕ), buf (Буферный элемент), not (Отрицание, НЕ).
В Verilog при использовании вентилей необходимо задать входы и выходы элемента, а также (не обязательно) имя вентиля. Например, вентили and и or должны иметь один выход и два и более входов. Так, для вентиля nor имеем
nor name listof arguments
nor mynor(out, in0, in1, in2, in3);
Добавим три команды
module R3 #(parameter ADDR_WIDTH = 2, DATA_WIDTH = 4)
(
input timer555, RAM_button,
input JMP, Z_JMP, PZ_JMP,
input [1:0] MUX_switch,
input Acc_button,
input Output_button,
input [3:0] data_in,
output [3:0] Acc,
output [3:0] data_out,
output [DATA_WIDTH-1:0] RAM,
output Z_flag, PZ_flag,
output reg [1:0] counter
);
wire [1:0] branch_adr;
assign branch_adr = data_in[1:0];
wire Z,PZ;
assign Z = Z_flag & Z_JMP;
assign PZ = PZ_flag & PZ_JMP;
//Counter
always @(posedge timer555)
begin
if(JMP|Z|PZ)
counter <= branch_adr;
else
counter <= counter + 1;
end
wire [ADDR_WIDTH-1:0] adr;
assign adr = counter;
//RAM
reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0];
always @(posedge RAM_button)
mem [adr] <= Acc;
assign RAM = mem[adr];
//sum
wire [3:0] sum;
assign sum = Acc + RAM;
//subtract
wire [3:0] subtract;
assign subtract = Acc - RAM;
//MUX
reg [3:0] MUX4;
always @*
MUX4 = MUX_switch[1] ? (MUX_switch[0] ? RAM : subtract)
: (MUX_switch[0] ? sum : data_in);
register4 Acc_reg(
.reg_data(MUX4),
.reg_clk(Acc_button),
.q(Acc)
);
register4 Output_reg(
.reg_data(Acc),
.reg_clk(Output_button),
.q(data_out)
);
assign Z_flag = ~(|Acc);
assign PZ_flag = ~Acc[3];
endmodule
Поместим команды и адреса в одно RAM/ОЗУ, а данные — в другое.
Схему можно скачать отсюда.
В первых восьми разрядах хранятся команды, в последних четырех разрядах хранится адрес, загружаемый в счётчик.
Вообще, загрузка числа в аккумулятор Асс должна производиться после переключения мультиплексора MUX (для команд ADD, SUB, LDA), по спаду тактового сигнала.
Т.о. в нашем компьютере следующая система команд
48х — ADD добавить число из ОЗУ к Асс
50х — SUB вычесть число, хранящееся в ОЗУ из Асс
80x — STA сохранить число из аккумулятора Асс в ОЗУ по адресу х
58х — LDA загрузить число из адреса х в Асс
04х — BRA безусловный переход в ячейку с адресом x
02х — BRZ переход в ячейку с адресом x, если Асс=0 (условный переход)
01x — BRP переход в ячейку с адресом x, если Асс>=0 (условный переход)
40х — INP загрузить число из data_input в Асс
20х — OUT загрузить число из Асс в data_out
Команды HLT у нас не будет.
Возьмём для примера алгоритм поиска максимального из двух чисел с сайта http://peterhigginson.co.uk/LMC/
Алгоритм работает так: сохраняем в память данных два числа из data_in. Вычитаем из второго числа первое:
00 INP 01 STA 11 02 INP 03 STA 12 04 SUB 11 05 BRP 08 06 LDA 11 07 BRA 09 08 LDA 12 09 OUT
В нашей системе команд этот алгоритм будет выглядеть так
400 80b 400 80c 50b 018 58b 049 58c 200
Элемент НЕ на управляющем входе счётчика, необходимый для загрузки данных в счётчик — это такая особенность программы Logisim, в реальных схемах элемент НЕ на управляющем входе не требуется (по крайней мере я таких счётчиков не знаю).
Quartus II можно скачать с официального сайта.
При регистрации в разделе My Primary Job Function is* необходимо выбрать пункт Student.
Далее необходимо скачать драйвер для программатора (драйвер для usb-blaster'a можно установить из C:\altera...\quartus\drivers\usb-blaster).
Перевод статьи Кена ШирриффаПочти каждый смартфон использует процессор на основе чипа ARM1, представленного в 1985 году. Более десяти миллиардов ядер ARM было использовано в различных гаджетах, включая один из самых больших провалов Apple, карманный компьютер Newton, и один из самых оглушительных её успехов — iPhone. В этой статье мы рассмотрим ключевые части процессора ARM1: опишем общую структуру чипа, посмотрим на то, как устроены транзисторы и как они функционируют, взаимодействуя друг с другом для хранения и обработки данных, а также взглянем на визуальную симуляцию этого микропроцессора и узнаем, что происходит внутри ARM1 во время его работы.