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