]> Joshua Wise's Git repositories - firearm.git/blob - Execute.v
Execute: Fix outbubble on multiplier so that it remembers to flush, fixing ldm_bonehe...
[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] spsr,
13         input [31:0] op0,
14         input [31:0] op1,
15         input [31:0] op2,
16         input carry,
17         
18         output reg outstall = 0,
19         output reg outbubble = 1,
20         output reg [31:0] outcpsr = 0,
21         output reg [31:0] outspsr = 0,
22         output reg write_reg = 1'bx,
23         output reg [3:0] write_num = 4'bxxxx,
24         output reg [31:0] write_data = 32'hxxxxxxxx,
25         output reg [31:0] jmppc,
26         output reg jmp,
27         output reg [31:0] outpc,
28         output reg [31:0] outinsn,
29         output reg [31:0] outop0, outop1, outop2
30         );
31         
32         reg mult_start;
33         reg [31:0] mult_acc0, mult_in0, mult_in1;
34         wire mult_done;
35         wire [31:0] mult_result;
36         
37         reg [31:0] alu_in0, alu_in1;
38         reg [3:0] alu_op;
39         reg alu_setflags;
40         wire [31:0] alu_result, alu_outcpsr;
41         wire alu_setres;
42         
43         reg next_outbubble;
44         reg [31:0] next_outcpsr, next_outspsr;
45         reg next_write_reg;
46         reg [3:0] next_write_num;
47
48         reg [31:0] next_write_data;
49
50         Multiplier multiplier(
51                 .clk(clk), .Nrst(Nrst),
52                 .start(mult_start), .acc0(mult_acc0), .in0(mult_in0),
53                 .in1(mult_in1), .done(mult_done), .result(mult_result));
54         
55         ALU alu(
56                 .clk(clk), .Nrst(Nrst),
57                 .in0(alu_in0), .in1(alu_in1), .cpsr(cpsr), .op(alu_op),
58                 .setflags(alu_setflags), .shifter_carry(carry),
59                 .result(alu_result), .cpsr_out(alu_outcpsr), .setres(alu_setres));
60
61         always @(posedge clk)
62         begin
63                 if (!stall)
64                 begin
65                         outbubble <= next_outbubble;
66                         outcpsr <= next_outcpsr;
67                         outspsr <= next_outspsr;
68                         write_reg <= next_write_reg;
69                         write_num <= next_write_num;
70                         write_data <= next_write_data;
71                         outpc <= pc;
72                         outinsn <= insn;
73                         outop0 <= op0;
74                         outop1 <= op1;
75                         outop2 <= op2;
76                 end
77         end
78         
79         reg delayedflush = 0;
80         always @(posedge clk)
81                 if (flush && outstall /* halp! I can't do it now, maybe later? */)
82                         delayedflush <= 1;
83                 else if (!outstall /* anything has been handled this time around */)
84                         delayedflush <= 0;
85
86         reg prevstall = 0;
87         always @(posedge clk)
88                 prevstall <= outstall;
89
90         always @(*)
91         begin
92                 outstall = stall;
93                 next_outbubble = inbubble | flush | delayedflush;
94                 next_outcpsr = cpsr;
95                 next_outspsr = spsr;
96                 next_write_reg = 0;
97                 next_write_num = 4'hx;
98                 next_write_data = 32'hxxxxxxxx;
99
100                 mult_start = 0;
101                 mult_acc0 = 32'hxxxxxxxx;
102                 mult_in0 = 32'hxxxxxxxx;
103                 mult_in1 = 32'hxxxxxxxx;
104
105                 alu_in0 = 32'hxxxxxxxx;
106                 alu_in1 = 32'hxxxxxxxx;
107                 alu_op = 4'hx;  /* hax! */
108                 alu_setflags = 1'bx;
109
110                 jmp = 1'b0;
111                 jmppc = 32'h00000000;
112
113                 casez (insn)
114                 `DECODE_ALU_MULT:       /* Multiply -- must come before ALU, because it pattern matches a specific case of ALU */
115                 begin
116                         if (!prevstall && !inbubble)
117                         begin
118                                 mult_start = 1;
119                                 mult_acc0 = insn[21] /* A */ ? op0 /* Rn */ : 32'h0;
120                                 mult_in0 = op1 /* Rm */;
121                                 mult_in1 = op2 /* Rs */;
122                                 $display("New MUL instruction");
123                         end
124                         outstall = outstall | ((!prevstall | !mult_done) && !inbubble);
125                         next_outbubble = next_outbubble | !mult_done | !prevstall;
126                         next_outcpsr = insn[20] /* S */ ? {mult_result[31] /* N */, mult_result == 0 /* Z */, 1'b0 /* C */, cpsr[28] /* V */, cpsr[27:0]} : cpsr;
127                         next_write_reg = 1;
128                         next_write_num = insn[19:16] /* Rd -- why the fuck isn't this the same place as ALU */;
129                         next_write_data = mult_result;
130                 end
131 //              `DECODE_ALU_MUL_LONG,   /* Multiply long */
132                 `DECODE_ALU_MRS:        /* MRS (Transfer PSR to register) */
133                 begin
134                         next_write_reg = 1;
135                         next_write_num = insn[15:12];
136                         if (insn[22] /* Ps */)
137                                 next_write_data = spsr;
138                         else
139                                 next_write_data = cpsr;
140                 end
141                 `DECODE_ALU_MSR,        /* MSR (Transfer register to PSR) */
142                 `DECODE_ALU_MSR_FLAGS:  /* MSR (Transfer register or immediate to PSR, flag bits only) */
143                         if ((cpsr[4:0] == `MODE_USR) || (insn[16] /* that random bit */ == 1'b0))       /* flags only */
144                         begin
145                                 if (insn[22] /* Ps */)
146                                         next_outspsr = {op0[31:29], spsr[28:0]};
147                                 else
148                                         next_outcpsr = {op0[31:29], cpsr[28:0]};
149                         end else begin
150                                 if (insn[22] /* Ps */)
151                                         next_outspsr = op0;
152                                 else
153                                         next_outcpsr = op0;
154                         end
155                 `DECODE_ALU_SWP,        /* Atomic swap */
156                 `DECODE_ALU_BX,         /* Branch */
157                 `DECODE_ALU_HDATA_REG,  /* Halfword transfer - register offset */
158                 `DECODE_ALU_HDATA_IMM:  /* Halfword transfer - immediate offset */
159                 begin end
160                 `DECODE_ALU:            /* ALU */
161                 begin
162                         alu_in0 = op0;
163                         alu_in1 = op1;
164                         alu_op = insn[24:21];
165                         alu_setflags = insn[20] /* S */;
166                         
167                         if (alu_setres) begin
168                                 next_write_reg = 1;
169                                 next_write_num = insn[15:12] /* Rd */;
170                                 next_write_data = alu_result;
171                         end
172                         
173                         next_outcpsr = ((insn[15:12] == 4'b1111) && insn[20]) ? spsr : alu_outcpsr;
174                 end
175                 `DECODE_LDRSTR_UNDEFINED,       /* Undefined. I hate ARM */
176                 `DECODE_LDRSTR,         /* Single data transfer */
177                 `DECODE_LDMSTM:         /* Block data transfer */
178                 begin end
179                 `DECODE_BRANCH:
180                 begin
181                         if(!inbubble && !flush && !delayedflush) begin
182                                 jmppc = pc + op0 + 32'h8;
183                                 if(insn[24]) begin
184                                         next_write_reg = 1;
185                                         next_write_num = 4'hE; /* link register */
186                                         next_write_data = pc + 32'h4;
187                                 end
188                                 jmp = 1'b1;
189                         end
190                 end                     /* Branch */
191                 `DECODE_LDCSTC,         /* Coprocessor data transfer */
192                 `DECODE_CDP,            /* Coprocessor data op */
193                 `DECODE_MRCMCR,         /* Coprocessor register transfer */
194                 `DECODE_SWI:            /* SWI */
195                 begin end
196                 default:                /* X everything else out */
197                 begin end
198                 endcase
199         end
200 endmodule
201
202 module Multiplier(
203         input clk,
204         input Nrst,     /* XXX not used yet */
205         
206         input start,
207         input [31:0] acc0,
208         input [31:0] in0,
209         input [31:0] in1,
210         
211         output reg done = 0,
212         output reg [31:0] result);
213         
214         reg [31:0] bitfield;
215         reg [31:0] multiplicand;
216         reg [31:0] acc;
217         
218         always @(posedge clk)
219         begin
220                 if (start) begin
221                         bitfield <= in0;
222                         multiplicand <= in1;
223                         acc <= acc0;
224                         done <= 0;
225                 end else begin
226                         bitfield <= {2'b00, bitfield[31:2]};
227                         multiplicand <= {multiplicand[29:0], 2'b00};
228                         acc <= acc +
229                                 (bitfield[0] ? multiplicand : 0) +
230                                 (bitfield[1] ? {multiplicand[30:0], 1'b0} : 0);
231                         if (bitfield == 0) begin
232                                 result <= acc;
233                                 done <= 1;
234                         end
235                 end
236         end
237 endmodule
238
239 module ALU(
240         input clk,
241         input Nrst,     /* XXX not used yet */
242
243         input [31:0] in0,
244         input [31:0] in1,
245         input [31:0] cpsr,
246         input [3:0] op,
247         input setflags,
248         input shifter_carry,
249
250         output reg [31:0] result,
251         output reg [31:0] cpsr_out,
252         output reg setres
253 );
254         reg [31:0] res;
255         reg flag_n, flag_z, flag_c, flag_v;
256         wire [32:0] sum, diff, rdiff;
257         wire sum_v, diff_v, rdiff_v;
258
259         assign sum = {1'b0, in0} + {1'b0, in1};
260         assign diff = {1'b0, in0} - {1'b0, in1};
261         assign rdiff = {1'b0, in1} + {1'b0, in0};
262         assign sum_v = (in0[31] ^~ in1[31]) & (sum[31] ^ in0[31]);
263         assign diff_v = (in0[31] ^ in1[31]) & (diff[31] ^ in0[31]);
264         assign rdiff_v = (in0[31] ^ in1[31]) & (rdiff[31] ^ in1[31]);
265
266         always @(*) begin
267                 res = 32'hxxxxxxxx;
268                 setres = 1'bx;
269                 flag_c = cpsr[`CPSR_C];
270                 flag_v = cpsr[`CPSR_V];
271                 case(op)
272                 `ALU_AND: begin
273                         result = in0 & in1;
274                         flag_c = shifter_carry;
275                         setres = 1'b1;
276                 end
277                 `ALU_EOR: begin
278                         result = in0 ^ in1;
279                         flag_c = shifter_carry;
280                         setres = 1'b1;
281                 end
282                 `ALU_SUB: begin
283                         {flag_c, result} = diff;
284                         flag_v = diff_v;
285                         setres = 1'b1;
286                 end
287                 `ALU_RSB: begin
288                         {flag_c, result} = rdiff;
289                         flag_v = rdiff_v;
290                         setres = 1'b1;
291                 end
292                 `ALU_ADD: begin
293                         {flag_c, result} = sum;
294                         flag_v = sum_v;
295                         setres = 1'b1;
296                 end
297                 `ALU_ADC: begin
298                         {flag_c, result} = sum + {32'b0, cpsr[`CPSR_C]};
299                         flag_v = sum_v | (~sum[31] & result[31]);
300                         setres = 1'b1;
301                 end
302                 `ALU_SBC: begin
303                         {flag_c, result} = diff - {32'b0, (~cpsr[`CPSR_C])};
304                         flag_v = diff_v | (diff[31] & ~result[31]);
305                         setres = 1'b1;
306                 end
307                 `ALU_RSC: begin
308                         {flag_c, result} = rdiff - {32'b0, (~cpsr[`CPSR_C])};
309                         flag_v = rdiff_v | (rdiff[31] & ~result[31]);
310                         setres = 1'b1;
311                 end
312                 `ALU_TST: begin
313                         result = in0 & in1;
314                         flag_c = shifter_carry;
315                         setres = 1'b0;
316                 end
317                 `ALU_TEQ: begin
318                         result = in0 ^ in1;
319                         flag_c = shifter_carry;
320                         setres = 1'b0;
321                 end
322                 `ALU_CMP: begin
323                         {flag_c, result} = diff;
324                         flag_v = diff_v;
325                         setres = 1'b0;
326                 end
327                 `ALU_CMN: begin
328                         {flag_c, result} = sum;
329                         flag_v = sum_v;
330                         setres = 1'b0;
331                 end
332                 `ALU_ORR: begin
333                         result = in0 | in1;
334                         flag_c = shifter_carry;
335                         setres = 1'b1;
336                 end
337                 `ALU_MOV: begin
338                         result = in1;
339                         flag_c = shifter_carry;
340                         setres = 1'b1;
341                 end
342                 `ALU_BIC: begin
343                         result = in0 & (~in1);
344                         flag_c = shifter_carry;
345                         setres = 1'b1;
346                 end
347                 `ALU_MVN: begin
348                         result = ~in1;
349                         flag_c = shifter_carry;
350                         setres = 1'b1;
351                 end
352                 endcase
353                 
354                 flag_z = (result == 0);
355                 flag_n = result[31];
356                 
357                 cpsr_out = setflags ? {flag_n, flag_z, flag_c, flag_v, cpsr[27:0]} : cpsr;
358         end
359 endmodule
This page took 0.043263 seconds and 4 git commands to generate.