
//mammal CPU
module mammal (
input clk,
input [15:0] data_in,
output logic [15:0] data_out,
output logic [11:0] address,
output memwt,
input INT,
output intack
);
logic [11:0] pc,ir; //program counter, instruction register
logic [11:0] interruptreg; //to hold temporary isr address during interrupt processing
logic [4:0] state; //FSM
logic [15:0] regbank [7:0];//registers
logic zeroflag; //zero flag register
logic intflag; //interrupt flag
logic [15:0] result; //output for ALU
logic zeroresult;
localparam FETCH=5'b00000,
LDI=5'b00001,
LD=5'b00010,
ST=5'b00011,
JZ=5'b00100,
JMP=5'b00101,
ALU=5'b00111,
PUSH=5'b01000,
POP1=5'b01001,
CALL=5'b01010,
RET1=5'b01011,
STI=5'b01100,
CLI=5'b01101,
IRET1=5'b01110,
POP2= 5'b10000,
RET2= 5'b10001,
IRET2=5'b10010,
IRET3=5'b10011,
INT1= 5'b10100,
INT2= 5'b10101,
INT3= 5'b10110;
always_ff @(posedge clk)
begin
case(state)
FETCH:
begin
if ( {1'b0,data_in[15:12] }==JZ)
if (zeroflag)
state <= JMP;
else
state <= FETCH;
else
state <= { 1'b0, data_in[15:12] };
ir<=data_in[11:0];
pc<=pc+1;
end
LDI:
begin
regbank[ ir[2:0] ] <= data_in;
pc<=pc+1;
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
LD:
begin
regbank[ir[2:0]] <= data_in;
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
ST:
begin
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
JMP:
begin
pc <= pc+ir;
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
ALU:
begin
regbank[ir[2:0]]<=result;
zeroflag<=zeroresult;
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
PUSH:
begin
regbank[7]<=regbank[7]-1;
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
POP1:
begin
regbank[7]<=regbank[7]+1;
state <= POP2;
end
POP2: //it is possible to eliminate pop2 by adding a register
begin
regbank[ir[2:0]] <= data_in;
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
CALL:
begin
regbank[7]<=regbank[7]-1;
pc<=pc+ir;
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
RET1:
begin
regbank[7]<=regbank[7]+1;
state <= RET2;
end
RET2:
begin
pc<=data_in[11:0];
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
INT1:
begin
regbank[7]<=regbank[7]-1;
intflag <= 0;
state <= INT2;
end
INT2:
begin
regbank[7]<=regbank[7]-1;
interruptreg <= 12'(data_in+16'h01f0); //Address of IDT is changed as 16'h01f0
state <= INT3;
end
INT3:
begin
pc<=data_in[11:0];
state <= FETCH;
end
IRET1:
begin
regbank[7]<=regbank[7]+1;
state <= IRET2;
end
IRET2:
begin
regbank[7]<=regbank[7]+1;
zeroflag <= data_in[0];
state <= IRET3;
end
IRET3:
begin
pc <= data_in;
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
STI:
begin
intflag <= 1;
if ( intflag & INT )
state <= INT1;
else
state <= FETCH;
end
CLI:
begin
intflag <= 0;
state <= FETCH;
end
endcase
end
//==============address========================
always_comb
case (state)
LD: address=regbank[ir[5:3]][11:0];
ST: address=regbank[ir[5:3]][11:0];
PUSH: address=regbank[7][11:0];
POP2: address=regbank[7][11:0];
CALL: address=regbank[7][11:0];
RET2: address=regbank[7][11:0];
INT1: address=regbank[7][11:0];
INT2: address=regbank[7][11:0];
INT3: address=interruptreg;
IRET1: address=regbank[7][11:0];
IRET2: address=regbank[7][11:0];
IRET3: address=regbank[7][11:0];
default: address=pc;
endcase
//================memwt===================================
assign memwt=(state==ST)||(state==PUSH)||(state==CALL) || (state==INT1) || (state==INT2);
//=================intack================================
always_comb
begin
case (state)
INT2: intack = 1'b1;
default: intack = 1'b0;
endcase
end
//================data_out=============================
always_comb
begin
case (state)
CALL: data_out = {4'b0,pc};
INT1: data_out = {4'b0,pc};
INT2: data_out = {15'b0, zeroflag};
default: data_out = regbank[ir[8:6]];
endcase
end
always_comb //ALU Operation
case (ir[11:9])
3'h0: result = regbank[ir[8:6]]+regbank[ir[5:3]]; //000
3'h1: result = regbank[ir[8:6]]-regbank[ir[5:3]]; //001
3'h2: result = regbank[ir[8:6]]®bank[ir[5:3]]; //010
3'h3: result = regbank[ir[8:6]]|regbank[ir[5:3]]; //011
3'h4: result = regbank[ir[8:6]]^regbank[ir[5:3]]; //100
3'h7: case (ir[8:6])
3'h0: result = !regbank[ir[5:3]];
3'h1: result = regbank[ir[5:3]];
3'h2: result = regbank[ir[5:3]]+1;
3'h3: result = regbank[ir[5:3]]-1;
default: result=16'h0000;
endcase
default: result=16'h0000;
endcase
assign zeroresult = ~|result;
initial
begin
state=FETCH;
zeroflag=0;
pc=0;
intflag=0; //at the start, interrupts are disabled. programmer must open them by a sti.
end
endmodule