]> Joshua Wise's Git repositories - firearm.git/blob - Execute.v
ram{.comments,}.hex: Add a simple orr instruction. Orr! Orr! I am a seal!
[firearm.git] / Execute.v
1 module Execute(
2         input clk,
3         input Nrst,     /* XXX not used yet */
4         
5         input stall,
6         input flush,
7         
8         input inbubble,
9         input [31:0] pc,
10         input [31:0] insn,
11         input [31:0] cpsr,
12         input [31:0] op0,
13         input [31:0] op1,
14         input [31:0] op2,
15         input carry,
16         
17         output reg outstall = 0,
18         output reg outbubble = 1,
19         output reg [31:0] outcpsr = 0,
20         output reg write_reg = 1'bx,
21         output reg [3:0] write_num = 4'bxxxx,
22         output reg [31:0] write_data = 32'hxxxxxxxx
23         );
24         
25         reg mult_start;
26         reg [31:0] mult_acc0, mult_in0, mult_in1;
27         wire mult_done;
28         wire [31:0] mult_result;
29         
30         reg [31:0] alu_in0, alu_in1;
31         reg [3:0] alu_op;
32         reg alu_setflags;
33         wire [31:0] alu_result, alu_outcpsr;
34         wire alu_set;
35         
36         Multiplier multiplier(
37                 .clk(clk), .Nrst(Nrst),
38                 .start(mult_start), .acc0(mult_acc0), .in0(mult_in0),
39                 .in1(mult_in1), .done(mult_done), .result(mult_result));
40         
41         ALU alu(
42                 .clk(clk), .Nrst(Nrst),
43                 .in0(alu_in0), .in1(alu_in1), .cpsr(cpsr), .op(alu_op),
44                 .setflags(alu_setflags), .shifter_carry(carry),
45                 .result(alu_result), .cpsr_out(alu_outcpsr), .set(alu_set));
46
47         always @(*)
48                 casez (insn)
49                 `DECODE_ALU_MULT,       /* Multiply -- must come before ALU, because it pattern matches a specific case of ALU */
50 //              `DECODE_ALU_MUL_LONG,   /* Multiply long */
51                 `DECODE_ALU_MRS,        /* MRS (Transfer PSR to register) */
52                 `DECODE_ALU_MSR,        /* MSR (Transfer register to PSR) */
53                 `DECODE_ALU_MSR_FLAGS,  /* MSR (Transfer register or immediate to PSR, flag bits only) */
54                 `DECODE_ALU_SWP,        /* Atomic swap */
55                 `DECODE_ALU_BX,         /* Branch */
56                 `DECODE_ALU_HDATA_REG,  /* Halfword transfer - register offset */
57                 `DECODE_ALU_HDATA_IMM,  /* Halfword transfer - immediate offset */
58                 `DECODE_ALU,            /* ALU */
59                 `DECODE_LDRSTR_UNDEFINED,       /* Undefined. I hate ARM */
60                 `DECODE_LDRSTR,         /* Single data transfer */
61                 `DECODE_LDMSTM,         /* Block data transfer */
62                 `DECODE_BRANCH,         /* Branch */
63                 `DECODE_LDCSTC,         /* Coprocessor data transfer */
64                 `DECODE_CDP,            /* Coprocessor data op */
65                 `DECODE_MRCMCR,         /* Coprocessor register transfer */
66                 `DECODE_SWI:            /* SWI */
67                 begin end
68                 default:                /* X everything else out */
69                 begin end
70                 endcase
71 endmodule
72
73 module Multiplier(
74         input clk,
75         input Nrst,     /* XXX not used yet */
76         
77         input start,
78         input [31:0] acc0,
79         input [31:0] in0,
80         input [31:0] in1,
81         
82         output reg done = 0,
83         output reg [31:0] result);
84         
85         reg [31:0] bitfield;
86         reg [31:0] multiplicand;
87         reg [31:0] acc;
88         
89         always @(posedge clk)
90         begin
91                 if (start) begin
92                         bitfield <= in0;
93                         multiplicand <= in1;
94                         acc <= acc0;
95                         done <= 0;
96                 end else begin
97                         bitfield <= {2'b00, bitfield[31:2]};
98                         multiplicand <= {multiplicand[29:0], 2'b00};
99                         acc <= acc +
100                                 (bitfield[0] ? multiplicand : 0) +
101                                 (bitfield[1] ? {multiplicand[30:0], 1'b0} : 0);
102                         if (bitfield == 0) begin
103                                 result <= acc;
104                                 done <= 1;
105                         end
106                 end
107         end
108 endmodule
109
110 /* XXX is the interface correct? */
111 module ALU(
112         input clk,
113         input Nrst,     /* XXX not used yet */
114
115         input [31:0] in0,
116         input [31:0] in1,
117         input [31:0] cpsr,
118         input [3:0] op,
119         input setflags,
120         input shifter_carry,
121
122         output reg [31:0] result,
123         output reg [31:0] cpsr_out,
124         output reg set
125 );
126         wire [31:0] res;
127         wire flag_n, flag_z, flag_c, flag_v, setres;
128         wire [32:0] sum, diff, rdiff;
129
130         assign sum = {1'b0, in0} + {1'b0, in1};
131         assign diff = {1'b0, in0} - {1'b0, in1};
132         assign rdiff = {1'b0, in1} + {1'b0, in0};
133
134         /* TODO XXX flag_v not set correctly */
135         always @(*) begin
136                 res = 32'hxxxxxxxx;
137                 setres = 1'bx;
138                 flag_c = cpsr[`CPSR_C];
139                 flag_v = cpsr[`CPSR_V];
140                 case(op)
141                 `ALU_AND: begin
142                         res = in0 & in1;
143                         flag_c = shifter_carry;
144                         setres = 1'b1;
145                 end
146                 `ALU_EOR: begin
147                         res = in0 ^ in1;
148                         flag_c = shifter_carry;
149                         setres = 1'b1;
150                 end
151                 `ALU_SUB: begin
152                         {flag_c, res} = diff;
153                         setres = 1'b1;
154                 end
155                 `ALU_RSB: begin
156                         {flag_c, res} = rdiff;
157                         setres = 1'b1;
158                 end
159                 `ALU_ADD: begin
160                         {flag_c, res} = sum;
161                         setres = 1'b1;
162                 end
163                 `ALU_ADC: begin
164                         {flag_c, res} = sum + {32'b0, cpsr[`CPSR_C]};
165                         setres = 1'b1;
166                 end
167                 `ALU_SBC: begin
168                         {flag_c, res} = diff - {32'b0, (~cpsr[`CPSR_C])};
169                         setres = 1'b1;
170                 end
171                 `ALU_RSC: begin
172                         {flag_c, res} = rdiff - {32'b0, (~cpsr[`CPSR_C])};
173                         setres = 1'b1;
174                 end
175                 `ALU_TST: begin
176                         res = in0 & in1;
177                         flag_c = shifter_carry;
178                         setres = 1'b0;
179                 end
180                 `ALU_TEQ: begin
181                         res = in0 ^ in1;
182                         flag_c = shifter_carry;
183                         setres = 1'b0;
184                 end
185                 `ALU_CMP: begin
186                         {flag_c, res} = diff;
187                         setres = 1'b0;
188                 end
189                 `ALU_CMN: begin
190                         {flag_c, res} = sum;
191                         setres = 1'b0;
192                 end
193                 `ALU_ORR: begin
194                         res = in0 | in1;
195                         flag_c = shifter_carry;
196                         setres = 1'b1;
197                 end
198                 `ALU_MOV: begin
199                         res = in1;
200                         flag_c = shifter_carry;
201                         setres = 1'b1;
202                 end
203                 `ALU_BIC: begin
204                         res = in0 & (~in1);
205                         flag_c = shifter_carry;
206                         setres = 1'b1;
207                 end
208                 `ALU_MVN: begin
209                         res = ~in1;
210                         flag_c = shifter_carry;
211                         setres = 1'b1;
212                 end
213                 endcase
214         end
215
216         always @(*) begin
217                 flag_z = (res == 0);
218                 flag_n = res[31];
219         end
220
221         always @(posedge clk) begin
222                 result <= res;
223                 cpsr_out <= setflags ? {flag_n, flag_z, flag_c, flag_v, cpsr[27:0]} : cpsr;
224                 set <= setres;
225         end
226
227 endmodule
This page took 0.035034 seconds and 4 git commands to generate.