aboutsummaryrefslogtreecommitdiff
path: root/cpu.sv
blob: 36c0bf2f461d60c3dc715423aecc07130665d5ad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
`define RST 5'b00000
`define GetA 5'b00001
`define GetB 5'b00010
`define operation 5'b00011
`define WriteReg 5'b00100
`define GetACMP 5'b00101
`define GetBCMP 5'b00110
`define GetBonly 5'b00111
`define IF1 5'b01000
`define IF2 5'b01001
`define UpdatePC 5'b01010
`define GetAddr 5'b01011
`define LoadAddr 5'b01100
`define StoreAddr 5'b01101
`define Dout 5'b01110
`define Dout2 5'b01111
`define Dout3 5'b10000
`define Dout4 5'b10001

`define MNONE 2'b00
`define MREAD 2'b01
`define MWRITE 2'b10

module cpu(clk,reset,read_data,write_data,mem_addr,mem_cmd,N,V,Z);
    input clk, reset;
    input [15:0] read_data;
    output reg [15:0] write_data;
    output reg [8:0] mem_addr;
    output reg [1:0] mem_cmd;
    output reg N, V, Z; 

    reg [15:0] inst_reg = 16'bx;
    reg [15:0] next_inst_reg, datapath_out;
    reg [2:0] opcode, readnum, writenum, Z_out;
    reg [1:0] op, nsel, shift, ALUop, vsel;
    reg loada, loadb, loadc, loads, write, asel, bsel, 
    load_ir, load_pc, reset_pc, addr_sel, load_addr;
    reg [15:0] sximm8;
    reg [15:0] sximm5;
    reg [4:0] present_state;

    reg [15:0] mdata;
    reg [8:0] PC, next_pc = 9'b0;
    reg [8:0] data_addr, next_data_addr;

    //three more internal wires
    //later change some of these to wires to make less expensive

    datapath DP(clk, readnum, vsel, loada, loadb, shift, asel, bsel, ALUop, 
                loadc, loads, writenum, write, Z_out, datapath_out, sximm5, sximm8, mdata);
    
    //if nsel == 00 -> rm nsel == 01 -> rd, nsel == 10 -> rn
    always_comb begin 
        
        {opcode, op} = inst_reg[15:11]; //decodin like crazy here
        if (opcode == 3'b100) shift = 2'b00;
        else shift = inst_reg[4:3];
        sximm5 = {{11{inst_reg[4]}}, inst_reg[4:0]};
        sximm8 = {{8{inst_reg[7]}} , inst_reg[7:0]}; //fix this back
        ALUop = op;

        case (nsel)
            2'b00: {readnum, writenum} = {2{inst_reg[2:0]}}; //Rm
            2'b01: {readnum, writenum} = {2{inst_reg[7:5]}}; //Rd
            2'b10: {readnum, writenum} = {2{inst_reg[10:8]}}; //Rn
            default: {readnum, writenum} = {writenum, readnum};
        endcase
        
        {Z, V, N} = Z_out; //give out all values
        write_data = datapath_out; 

        mdata = read_data;
        next_inst_reg = load_ir ? read_data : inst_reg; //load for instructions

        next_pc = reset_pc ? 9'b0 : (PC + 1'b1);
        mem_addr = addr_sel ? PC : data_addr;
        next_data_addr = load_addr ? datapath_out[8:0] : data_addr;
    end
    
    // next: first, second and third bit: nsel, second bit loada, third bit loadB, fouth bit asel, 
    // fifth bit bsel, sixth and 7th bit shift, 8th and 9th bit aluop, 10th bit loadc, 11bit vsel, 
    // 12bit write  
    always_ff @(posedge clk) begin
        inst_reg = next_inst_reg;
        data_addr = next_data_addr;
        if (load_pc) PC = next_pc;
        
        casex ({present_state, reset}) 
            //all roads lead to rome (`wait)
            {4'bxxxx, 1'b1} : {present_state, write, load_pc, reset_pc, load_ir} = {`RST, 4'b0110};
            {`RST, 1'b0} : {present_state, write, addr_sel, load_pc, reset_pc, mem_cmd} = {`IF1, 4'b0100, `MREAD};
            {`IF1, 1'b0} : {present_state, load_ir} = {`IF2, 1'b1};
            {`IF2, 1'b0} : {present_state, addr_sel, load_pc, load_ir, mem_cmd} = {`UpdatePC, 3'b010, `MNONE};
            //make IF1 states+, last state before below is UpdatePC

            {`UpdatePC, 1'b0} : begin
                casex ({opcode, op}) //op since ALUop == op
                    //move instructions
                    5'b11010: {present_state, nsel, vsel, write, load_pc} = {`WriteReg, 6'b101010}; // 2 clk cycles
                    5'b11000: {present_state, nsel, loada, loadb, load_pc} = {`GetBonly, 5'b00010}; // 3 clk cycles
                    //alu instructions
                    5'b101x0: {present_state, nsel, loada, load_pc} = {`GetA, 4'b1010}; //ADD & AND ---> 4 clk cycles //loads A
                    5'b10101: {present_state, nsel, loada, load_pc} = {`GetACMP, 4'b1010};  //CMP ---> 3 clk cycles //loads A
                    5'b10111: {present_state, nsel, loada, loadb, load_pc} = {`GetBonly, 5'b00010}; //MVN ---> 3 clk cycles //loads to B
                    //memory instructions
                    5'b01100: {present_state, nsel, loada, loadb, asel, bsel, load_pc, mem_cmd} = {`GetAddr, 7'b1010010, `MREAD}; //LDR
                    5'b10000: {present_state, nsel, loada, loadb, asel, bsel, load_pc} = {`GetAddr, 7'b1010010}; //STR
                    //HALT instruction
                    5'b111xx: {present_state, load_pc} = {`UpdatePC, 1'b0}; //will be stuck here until reset
                endcase
            end
            
            //ADD & AND branch
            {`GetA, 1'b0} : {present_state, nsel, loadb, loada} = {`GetB, 4'b0010}; //loads B
            {`GetB, 1'b0} : {present_state, asel, bsel, loadc, loads} = {`operation,  4'b0010}; //performs operations

            //for writing only from B to Rd
            {`GetBonly, 1'b0} : {present_state, asel, bsel, loadc, loads} = {`operation, 4'b1010};

            //Get the (shifted) memory address (LDR)
            {`GetAddr, 1'b0} : begin
                case (opcode) 
                    3'b011: {present_state, loada, loadb, loadc, load_addr, addr_sel, mem_cmd} = {`Dout, 5'b00110, `MREAD}; //might need an extra state for dout
                    3'b100: {present_state, loada, loadb, loadc, load_addr, addr_sel} = {`StoreAddr, 5'b00110};
                endcase  
            end
            {`Dout, 1'b0} : begin //wait for RAM
                case (opcode) 
                    3'b011: present_state = `Dout2;
                    3'b100: {present_state, loada, loadb, loadc, load_addr, mem_cmd} = {`Dout4, 4'b0010, `MWRITE};
                endcase
            end
            {`Dout2, 1'b0} : {present_state, load_addr} = {`LoadAddr, 1'b0};
            {`LoadAddr, 1'b0} : {present_state, nsel, vsel, write, loadc, load_addr, mem_cmd} = {`Dout3, 7'b0111100, `MREAD};
            {`Dout3, 1'b0} : {present_state, mem_cmd, write} = {`WriteReg, `MNONE, 1'b0};

            {`StoreAddr, 1'b0} : {present_state, nsel, loada, loadb, asel, bsel, load_addr} = {`Dout, 7'b0101101};
            {`Dout4, 1'b0} : {present_state, write} = {`WriteReg, 1'b0};

            //CMP branch
            {`GetACMP, 1'b0} : {present_state, nsel, loadb, loada} = {`GetBCMP, 4'b0010}; //loads B
            {`GetBCMP, 1'b0} : {present_state, asel, bsel, loadc, loads} = {`WriteReg,  4'b0001}; //performs operations and writes into status

            //write to Rd
            {`operation, 1'b0} : {present_state, nsel, vsel, write} = {`WriteReg, 5'b01001}; //writing into the register
             //waiter/reset
            {`WriteReg, 1'b0} : {present_state, loada, loadb, loadc, loads, mem_cmd} = {`RST, 4'b0000, `MNONE}; //extra cycle for values to got through (should I go reset or IF1)
        endcase      
    end
 endmodule