МАРСОХОД

Open Source Hardware Project

Добро пожаловать, Гость
Логин: Пароль: Запомнить меня

ТЕМА: Минималистичное софт-ядро для Марсохода.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4882

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
У меня раньше были только 2х-уровневые конвейеры, поэтому новые велосипеды изобретать пришлось. Как покороче описать блок управления, и тп.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4883

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
Перевел в потактовую Си-модель, и сразу нашел/исправил 2 мелкие ошибки: 1) забыл, что PC надо дважды инкрементировать в командах переходов (выборка imm), 2) запись в аккумулятор была аж на 4-ом такте...

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4884

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
Еще мелкие ошибки нашел, теперь в Си-модели заработала и косвенная адресация.
Попробую все-таки перенести тесты в IcarusVerilog.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4885

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
Заработало в IcarusVerilog. Мелкие программы ввожу прямо в машинных кодах. Выявилась логическая ошибка: RET Rn, это уже косвенная адресация, соответственно RET @Rn - косвенно-косвенная, а в блоке управления такое пока не предусмотрено. Потом добавлю.
Сегодня-завтра выложу Верилоговский файл.
Для тестов память описана без использования альтеровских примитивов, это добавляет некоторую логику для addressstall.

По поводу 32-разрядной версии - это просто д/б другой проект, тк команды не будут совместимы из-за байтовой адресации. В 16-разрядной версии под команду отводится 1 младший бит (чтобы не терять разряды) и 5 старших, а в 32-разрядной - 2 младших и 4 старших. Те кодировка будет разная.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Последнее редактирование: от Leka.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4886

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
///////////////////////////////////////////////////////////////////////////////
module tb();
reg clk=0; always #1 clk<=~clk;
reg en=0;
reg start=0;
reg reset=0;
wire [15:0]pc;
wire [15:0]acc;
top _(clk,en,start,reset,pc,acc);
always@(posedge clk) $strobe("pc=%3d  acc=%5d",pc, acc);
initial begin
	@(posedge clk); en=1; start=1;
	@(posedge clk); start=0;
	#120 $finish;
end
endmodule
///////////////////////////////////////////////////////////////////////////////
module memas#(parameter N=10, parameter W=16)
	(clk,qA,dA,aA,asA,weA,qB,dB,aB,asB,weB);
input clk;
input [N-1:0] aA;
input [N-1:0] aB;
input [W-1:0] dA;
input [W-1:0] dB;
input asA;
input asB;	
input weA;
input weB;
output reg [W-1:0] qA=0;
output reg [W-1:0] qB=0;
reg [W-1:0] ram [2**N-1:0];
reg [N-1:0] aAreg=0, aBreg=0;
wire [N-1:0] aAsel = asA ? aAreg : aA;
wire [N-1:0] aBsel = asB ? aBreg : aB;	
always@(posedge clk) aAreg<=aA;
always@(posedge clk) aBreg<=aB;
always@(posedge clk) if(weA) ram[aAsel]<=dA;	
always@(posedge clk) if(weB) ram[aBsel]<=dB;	
always@(posedge clk) qA<=weA?dA:ram[aAsel];		
always@(posedge clk) qB<=weB?dB:ram[aBsel];	
integer i;
initial begin
	for(i=0;i<2**N;i=i+1)ram[i]=16'h0000;

	ram[0000>>1]= 100;
	ram[1000>>1]= 0;
	ram[1002>>1]= 1;
	ram[1004>>1]= 7;
	ram[1006>>1]= 1000;
	ram[1008>>1]= 1002;
	ram[1010>>1]= 1004;
	ram[1012>>1]= 1020;
	
	ram[10>>1]= 15<<12 | 1<<11 | 1020 | 0;  //CALL R1020, 20	
	ram[12>>1]= 20;	
	ram[14>>1]= 2<<12 | 0<<11 | 1000 | 0;  //LD R1000
	ram[20>>1]= 5<<12 | 0<<11 | 1002 | 0;  //ADD R1002 	
	ram[22>>1]= 14<<12 | 1<<11 | 1004 | 0;  //LT R1004, 20		
	ram[24>>1]= 20;		
	
	// ram[10>>1]= 15<<12 | 1<<11 | 1012 | 1;  //CALL @R1012, 20	
	// ram[12>>1]= 20;
	// ram[14>>1]= 2<<12 | 0<<11 | 1006 | 1;  //LD @R1006	
	// ram[20>>1]= 5<<12 | 0<<11 | 1008 | 1; 	 //ADD @R1008 	
	// ram[22>>1]= 14<<12 | 1<<11 | 1010 | 1; //LT @R1010, 20		
	// ram[24>>1]= 20;	
	
	ram[26>>1]=	0<<12 | 1<<11 | 1020 | 1;	//RET R1020
end
endmodule
///////////////////////////////////////////////////////////////////////////////
`define nop_op		(cmd[4:1]==0)
`define st_op			(cmd[4:1]==1)
`define ld_op			(cmd[4:1]==2)
`define com_op		(cmd[4:1]==3)
`define neg_op 		(cmd[4:1]==4)
`define add_op	  		(cmd[4:1]==5)
`define sub_op	    		(cmd[4:1]==6)
`define and_op			(cmd[4:1]==7)
`define or_op	 		(cmd[4:1]==8)
`define xor_op  		(cmd[4:1]==9)
`define asl_op			(cmd[4:1]==10)
`define asr_op  		(cmd[4:1]==11)
`define eq_op			(cmd[4:1]==12)
`define ne_op   		(cmd[4:1]==12)
`define gt_op	    		(cmd[4:1]==13)
`define le_op			(cmd[4:1]==13)
`define ge_op			(cmd[4:1]==14)
`define lt_op		    	(cmd[4:1]==14)
`define call_op			(cmd[4:1]==15)
`define ret_op			(cmd[4:0]==1)
`define jcom_op		(cmd[0])
///////////////////////////////////////////////////////////////////////////////
//`define cmdJCOM	(ret_op||call_op||ne_op||lt_op||le_op)
`define cmdJCOM		(`jcom_op)
`define cmdA	    		(`nop_op||`st_op||`add_op||`sub_op||`and_op||`or_op||`xor_op)
`define cmdAN	    	(`eq_op||`ne_op)
`define cmdB	    		(`ld_op||`add_op) 
`define cmdBN	    	(`com_op||`neg_op||`sub_op) 
`define cmdINT    		(`gt_op||`ge_op||`lt_op||`le_op)
`define cmdASL		(`asl_op) 
`define cmdASR		(`asr_op) 
`define cmdAND		(`and_op) 
`define cmdOR		(`or_op)
`define cmdXOR		(`xor_op||`eq_op||`ne_op) 
`define cmdC    		(`neg_op||`sub_op||`eq_op||`ne_op||`ge_op||`lt_op)
`define cmdJCMP  		(`eq_op||`ne_op||`gt_op||`ge_op||`lt_op||`le_op)
`define cmdCALL 		(`call_op)
///////////////////////////////////////////////////////////////////////////////
`define INDIR			(qA[0])
`define ST			(((qA>>12)&15)==1)
`define RS			(((qA>>11)&31)==1)
`define LD			(`ld_op||`com_op||`neg_op||`add_op||`sub_op||`and_op||`or_op||`xor_op||`asl_op||`asr_op)
`define BR			(`eq_op||`ne_op||`gt_op||`le_op||`ge_op||`lt_op||`call_op)
///////////////////////////////////////////////////////////////////////////////
module top(CLOCK_50,en,start,reset,pc,acc);
input CLOCK_50;
input en;
input start;
input reset;
output [15:0]pc;
output [15:0]acc;
core#(10) _0(CLOCK_50,en,start,reset,pc,acc);
endmodule
//----------------------------------
module core#(parameter N=10)(clk,en,start,reset,pc,acc);
input clk;
input en;
input start;
input reset;
output [15:0]pc;
output [15:0]acc;
wire [15:0]qA;
wire [15:0]aA;
wire [15:0]qB;
wire [15:0]dB;
wire [15:0]aB;
wire [15:0]Y;
wire C;
wire asB;
wire weB;
wire wePC;
wire weACC;
wire [4:0]cmd;
wire [4:0] qAcmd=qA[15:11];
wire JCOM;
wire K;
memas#(N,16)_1(clk,qA,0,aA[N:1],0,0,qB,dB,aB[N:1],asB,weB);
fsm _2(clk,K,weACC,wePC,cmd,qAcmd,qA,start,en);
selB _3(JCOM,asB,weB,aB,dB,qA,Y,pc,cmd,K);
rgPC _4(clk,pc,aA,aB,C,wePC,reset,K);
rgACC _5(clk,acc,Y,0,0,weACC);
alu _6(C,Y,acc,qB,cmd,JCOM);
endmodule
//----------------------------------
module selB(JCOM,asB,weB,aB,dB,qA,Y,pc,cmd,K);
output JCOM;
output asB;
output weB;
output [15:0]aB;
output [15:0]dB;
input [15:0]qA;
input [15:0]Y;
input [15:0]pc;
input [4:0]cmd;
input K;
assign JCOM=`cmdJCOM|(K&`INDIR);
assign asB=`call_op;
assign weB=(`st_op||`call_op)|(`ST&K&~`INDIR);
assign aB=K?qA[10:0]:qA;
assign dB=`cmdCALL?pc:Y;
endmodule
//----------------------------------
module rgPC(clk,pc,aA,aB,C,wePC,reset,K);
input clk;
output [15:0]pc;
output [15:0]aA;
input [15:0]aB;
input C;
input wePC;
input reset;
input K;
reg [15:0]pc0=0;
assign pc=pc0+2;
assign aA=C?aB:pc;
always@(posedge clk)begin
	if(wePC) pc0<=aA;
	if(reset) pc0<=0;
end
endmodule
//----------------------------------
module rgACC(clk,acc,Y,dE,selE,weACC);
input clk;
output reg [15:0]acc=0;
input [15:0]Y;
input [15:0]dE;
input selE;
input weACC;
always@(posedge clk) if(weACC) acc<=selE?dE:Y;
endmodule
//----------------------------------
module fsm(clk,K,weACC,wePC,qcmd,cmd,qA,start,en);
input clk;
output K;
output weACC;
output wePC;
output [4:0]qcmd;
input [4:0]cmd;
input [15:0]qA;
input start;
input en;
reg [2:0]sK=0;
reg [2:0]sweACC=0;
reg [2:0]swePC=0;
reg [9:0]scmd=0;
assign K=sK[0]; 
assign qcmd=scmd[4:0];
assign weACC=sweACC[0];
assign wePC=swePC[0]|(K&~`INDIR);
always@(posedge clk)begin
	sK<=sK>>1;
	sweACC<=sweACC>>1;
	swePC<=swePC>>1;
	scmd<=scmd>>5;
	if(K|start)begin
		if(`INDIR) begin
			if(`LD) sweACC[1]<=1;
			if(!`ST & !`RS) scmd[9:5]<=cmd; else scmd[4:0]<=cmd;
			if(`BR) sK[2]<=en; else sK[1]<=en;
			if(`BR) swePC[1:0]<=3; else swePC[0]<=1; 			
		end else begin
			if(`LD) sweACC[0]<=1;
			if(!`ST) scmd[4:0]<=cmd;	
			if(`BR) sK[1]<=en; else sK[0]<=en;
			if(`BR) swePC[0]<=1; 
		end
	end
end
endmodule
//----------------------------------
module alu(C,Y,a,b,cmd,JCOM);
output C;
output [15:0]Y;
input [15:0]a;
input [15:0]b;
input [4:0]cmd;
input JCOM;
wire [15:0]qa;
wire [15:0]qs;
wire [15:0]qb;
wire [15:0]qL;
alua _10(qa,a,cmd);
alus _11(qs,a,cmd);
alub _12(qb,qs,b,cmd);
aluL _13(qL,qa,b,cmd);
aluY _14(Y,C,qL,qb,cmd,JCOM);
endmodule
//----------------------------------
module alua(q,a,cmd);
output [15:0]q;
input [15:0]a;
input [4:0]cmd;
assign q = 
	`cmdA ? a : 
	`cmdAN ? ~a : 
	`cmdINT ? a ^ 'h8000 : 
	0; 
endmodule
//----------------------------------
module alus(q,a,cmd);
output [15:0]q;
input [15:0]a;
input [4:0]cmd;
assign q =
	`cmdASL ? {a[14:0], 1'b0}  : 
	`cmdASR ? {a[15], a[15:1]} :  
	0; 
endmodule
//----------------------------------
module alub(q,a,b,cmd);
output [15:0]q;
input [15:0]a;
input [15:0]b;
input [4:0]cmd;
assign q = 
	`cmdB ? b : 
	`cmdBN ? ~b : 
	`cmdINT ? b ^ 'h7FFF : 
	a; 
endmodule
//----------------------------------
module aluL(q,a,b,cmd);
output [15:0]q;
input [15:0]a;
input [15:0]b;
input [4:0]cmd;
assign q = 
	`cmdAND ? a & b :
	`cmdOR ?  a | b :
	`cmdXOR ? a ^ b :
	a; 
endmodule
//----------------------------------
module aluY(Y,C,a,b,cmd,JCOM);
output [15:0]Y;
output C;
input [15:0]a;
input [15:0]b;
input [4:0]cmd;
input JCOM;
wire [17:0] q = {JCOM, `cmdJCMP, a} + b + `cmdC;
assign Y=q; 
assign C=q[17];
endmodule
//----------------------------------
Вложения:

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Последнее редактирование: от Leka.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4887

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
Транслятор symbolic-->asm у меня на Паскале. Разберусь с делами, буду делать транслятор в машинные коды. Потом можно будет перевести в Си для открытого проекта.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4888

IcarusVerilog не имею. Сделал проект в Active-HDL.
Промоделировал. ACC в цикле считает от 0 до 7.
Это верно?
Описание кодов команд есть?

Николай.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4889

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
Если в IcarusVerilog заработает, то в других и подавно. Просто это самый маленький симулятор.
Да, в цикле считает от 0 до 7. Опкоды завтра напишу/выложу, сам смотрю в `define в исходниках, другой таблички нет.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4890

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54
Команда = Маска_опкода | Номер_регистра << 1 | Метод_адресации.
Номер_регистра: 10 бит.
Метод_адресации: 1 бит, прямой = 0, косвенный = 1.
Маска_опкода:
NOP 0x0000
ST 0x1000
LD 0x2000
COM 0x3000
NEG 0x4000
ADD 0x5000
SUB 0x6000
AND 0x7000
OR 0x8000
XOR 0x9000
ASL 0xA000
ASR 0xB000
EQ 0xC000
NE 0xC800
GT 0xD000
LE 0xD800
GE 0xE000
LT 0xE800
CALL 0xF800
RET 0x0801 // Потом будет 0x0800

1) NOP используется аппаратно в конвейере, менять/замещать/удалять нельзя. В коде использовать не обязательно.
2) RET поменяю, чтобы ортогонализировать систему команд (добавив косвенно-косвенную адресацию RET @Rn).
3) У меня используется сигнал addressstall, который аппаратно реализован только у Альтеры. Нужен только для команды CALL, чтобы записать в регистр правильное значение PC, после выборки imm адреса перехода. Вместо этого можно дополнительно поставить сумматор PC+2, и отказаться от addressstall. Это упростит логику ядра, и сделает его универсальным. Наверно, так и сделаю.
4) Не нравится, как пока задумано чтение внешних устройств - через мультиплексор записи в аккумулятор. Придет лучшее решение, поменяю.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Минималистичное софт-ядро для Марсохода. 3 года 10 мес. назад #4891

  • Leka
  • Leka аватар Автор темы
  • Не в сети
  • Живу я здесь
  • Живу я здесь
  • Сообщений: 635
  • Спасибо получено: 54

Ynicky пишет: А может сделать процессор 32-х разрядным, с 16-ти разрядными командами?

Кстати, какая м/б цель такого проекта? Имхо, 16-разрядная аккумуляторная система команд не уменьшит объем кода по сравнению с 32-разрядной регистровой, поэтому единственный смысл - просто иметь возможность увеличить разрядность АЛУ с минимальной переделкой компилятора/ассемблера.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Время создания страницы: 0.512 секунд

ВКонтакте  facebook  GitHub  YouTube  Twitter
Вы здесь: Начало Forum Наш форум Проекты пользователей Минималистичное софт-ядро для Марсохода.