Skip to content

Bird: in Verilog

Bird FSM

Verilog CodeĀ 

//bird CPU
module bird (
        input clk,
        input [15:0] data_in,
        output logic [15:0] data_out,
        output logic [11:0] address,
        output memwt
        );

logic [11:0] pc,ir; //program counter, instruction register

logic [4:0] state; //FSM
logic [15:0] regbank [7:0];//registers 
logic zeroflag; //zero flag register
logic [15:0] result; //output for result
 
 
localparam    FETCH=4'b0000,
        LDI=4'b0001, 
        LD=4'b0010,
        ST=4'b0011,
        JZ=4'b0100,
        JMP=4'b0101,
        ALU=4'b0111,
        PUSH=4'b1000,
        POP1=4'b1001,
        POP2=4'b1100,
        CALL=4'b1010,
        RET1=4'b1011,
        RET2=4'b1101;
 

logic zeroresult; 

always_ff @(posedge clk)
    case(state) 
        FETCH: 
            begin
                if ( data_in[15:12]==JZ) // if instruction is jz  
                    if (zeroflag)  //and if last bit of 7th register is 0 then jump to jump instruction state
                        state <= JMP;
                    else
                        state <= FETCH; //stay here to catch next instruction
                else
                    state <= data_in[15:12]; //read instruction opcode and jump the state of the instruction to be read
                ir<=data_in[11:0]; //read instruction details into instruction register
                pc<=pc+1; //increment program counter
            end

        LDI:
            begin
                regbank[ ir[2:0] ] <= data_in; 
                pc<=pc+1; //for next instruction (32 bit instruction)  
                state <= FETCH;
            end

        LD:
            begin
                regbank[ir[2:0]] <= data_in;
                state <= FETCH;  
            end 
 
        ST:
            begin
                state <= FETCH;  
            end
 
        JMP:
            begin
                pc <= pc+ir;
                state <= FETCH;  
            end
 
        ALU:
            begin
                regbank[ir[2:0]]<=result;
                zeroflag<=zeroresult;
                state <= FETCH;
            end

        PUSH:
            begin
                 regbank[7]<=regbank[7]-1;
                 state <= FETCH;
            end

        POP1:
            begin
                regbank[7]<=regbank[7]+1;
                state <= POP2;
            end

        POP2: //actually unnecessary
            begin
                regbank[ir[2:0]] <= data_in;
                state <= FETCH; 
            end

        CALL: 
            begin
                regbank[7]<=regbank[7]-1;
                pc<=pc+ir;
                state <= FETCH; 
            end

        RET1:
            begin
                regbank[7]<=regbank[7]+1;
                state <= RET2;
            end

        RET2:
            begin
                pc<=data_in[11:0];
                state <= FETCH; 
            end

    endcase

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];
        default: address=pc;
    endcase
 
 
assign memwt=(state==ST)||(state==PUSH)||(state==CALL);
 
always_comb
    case (state)
        CALL: data_out = {4'b0,pc};
        default: data_out = regbank[ir[8:6]];
    endcase

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]]&regbank[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;
end

endmodule