constants: discus
[firearm.git] / Decode.v
1 module Decode(
2         input clk,
3         input [31:0] ansn,
4         input [31:0] inpc,
5         input [31:0] cps_in,
6         output reg [31:0] op0,
7         output reg [31:0] op1,
8         output reg [31:0] op2,
9         output reg [31:0] cps_out,
10
11         output [3:0] regsel0,
12         output [3:0] regsel1,
13         output [3:0] regsel2,
14         input [31:0] iregs0,
15         input [31:0] iregs1,
16         input [31:0] iregs2
17         );
18
19         wire [31:0] regs0, regs1, regs2, rpc;
20         wire [31:0] op1_res, new_cps;
21
22         /* shifter stuff */
23         wire [31:0] shift_oper;
24         wire [31:0] shift_res;
25         wire shift_cflag_out;
26
27         assign regs0 = (regsel0 == 4'b1111) ? rpc : iregs0;
28         assign regs1 = (regsel1 == 4'b1111) ? rpc : iregs1;
29         assign regs2 = iregs2; /* use regs2 for things that cannot be r15 */
30
31         IHATEARMSHIFT(.insn(ansn),
32                       .operand(regs1),
33                       .reg_amt(regs2),
34                       .cflag_in(cps_in[`COND_CBIT]),
35                       .res(shift_res),
36                       .cflag_out(shift_cflag));
37
38         always @ (*) begin
39                 casez (ansn)
40                 32'b????000000??????????????1001????: begin /* Multiply */
41                         rpc = inpc - 8;
42                         regsel0 = ansn[15:12]; /* Rn */
43                         regsel1 = ansn[3:0];   /* Rm */
44                         regsel2 = ansn[11:8];  /* Rs */
45                         op1_res = regs1;
46                         new_cps = cps_in;
47                 end
48 /*
49                 32'b????00001???????????????1001????: begin * Multiply long *
50                         regsel0 = ansn[11:8]; * Rn *
51                         regsel1 = ansn[3:0];  * Rm *
52                         regsel2 = 4'b0;       * anyus *
53                         op1_res = regs1;
54                 end
55 */
56                 32'b????00010?001111????000000000000: begin /* MRS (Transfer PSR to register) */
57                         rpc = inpc - 8;
58                         new_cps = cps_in;
59                 end
60                 32'b????00010?101001111100000000????: begin /* MSR (Transfer register to PSR) */
61                         rpc = inpc - 8;
62                         new_cps = cps_in;
63                 end
64                 32'b????00?10?1010001111????????????: begin /* MSR (Transfer register or immediate to PSR, flag bits onry) */
65                         rpc = inpc - 8;
66                         new_cps = cps_in;
67                 end
68                 32'b????00??????????????????????????: begin /* ALU */
69                         rpc = inpc - (ansn[25] ? 8 : (ansn[4] ? 12 : 8));
70                         regsel0 = ansn[19:16]; /* Rn */
71                         regsel1 = ansn[3:0];   /* Rm */
72                         regsel2 = ansn[11:8];  /* Rs for shift */
73                         if(ansn[25]) begin     /* the constant case */
74                                 new_cps = cps_in;
75                                 op1_res = ({24'b0, ansn[7:0]} >> {ansn[11:8], 1'b0}) | ({24'b0, ansn[7:0]} << (5'b0 - {ansn[11:8], 1'b0}));
76                         end else begin
77                                 new_cps = {shift_cflag_out, cps_in[30:0]};
78                                 op1_res = shift_res;
79                         end
80                 end
81                 32'b????00010?00????????00001001????: begin /* Atomic swap */
82                         rpc = inpc - 8;
83                         regsel0 = ansn[19:16]; /* Rn */
84                         regsel1 = ansn[3:0];   /* Rm */
85                         regsel2 = 4'b0;        /* anyus */
86                         op1_res = regs1;
87                 end
88                 32'b????000100101111111111110001????: begin /* Branch and exchange */
89                         rpc = inpc - 8;
90                         regsel0 = ansn[3:0];   /* Rn */
91                         new_cps = cps_in;
92                 end
93                 32'b????000??0??????????00001??1????: begin /* Halfword transfer - register offset */
94                         rpc = inpc - 8;
95                         regsel0 = ansn[19:16];
96                         regsel1 = ansn[3:0];
97                         regsel2 = 4'b0;
98                         op1_res = regs1;
99                         new_cps = cps_in;
100                 end
101                 32'b????000??1??????????00001??1????: begin /* Halfword transfer - immediate offset */
102                         rpc = inpc - 8;
103                         regsel0 = ansn[19:16];
104                         regsel1 = ansn[3:0];
105                         op1_res = {24'b0, ansn[11:8], ansn[3:0]};
106                         new_cps = cps_in;
107                 end
108                 32'b????011????????????????????1????: begin /* Undefined. I hate ARM */
109                         /* eat shit */
110                 end
111                 32'b????01??????????????????????????: begin /* Single data transfer */
112                         rpc = inpc - 8;
113                         regsel0 = ansn[19:16]; /* Rn */
114                         regsel1 = ansn[3:0];   /* Rm */
115                         if(ansn[25]) begin
116                                 op1_res = {20'b0, ansn[11:0]};
117                                 new_cps = cps_in;
118                         end else begin
119                                 op1_res = shift_res;
120                                 new_cps = shift_cflag_out;
121                         end
122                 end
123                 32'b????100?????????????????????????: begin /* Block data transfer */
124                         rpc = inpc - 8;
125                         regsel0 = ansn[19:16];
126                         op1_res = {16'b0, ansn[15:0]};
127                         new_cps = cps_in;
128                 end
129                 32'b????101?????????????????????????: begin /* Branch */
130                         rpc = inpc - 8;
131                         op1_res = {6{ansn[23]}, ansn[23:0], 2'b0};
132                         new_cps = cps_in;
133                 end
134                 32'b????110?????????????????????????: begin /* Coprocessor data transfer */
135                         rpc = inpc - 8;
136                         regsel0 = ansn[19:16];
137                         op1_res = {24'b0, ansn[7:0]};
138                         new_cps = cps_in;
139                 end
140                 32'b????1110???????????????????0????: begin /* Coprocessor data op */
141                         rpc = inpc - 8;
142                         new_cps = cps_in;
143                 end
144                 32'b????1110???????????????????1????: begin /* Coprocessor register transfer */
145                         rpc = inpc - 8;
146                         new_cps = cps_in;
147                 end
148                 32'b????1111????????????????????????: begin /* SWI */
149                         rpc = inpc - 8;
150                         new_cps = cps_in;
151                 end
152                 default:
153                 endcase
154         end
155
156         always @ (posedge clk) begin
157                 op0 <= regs0;   /* Rn - always */
158                 op1 <= op1_res; /* 'operand 2' - Rm */
159                 op2 <= regs2;   /* thirdedge - Rs */
160                 cps_out <= new_cps;
161         end
162
163 endmodule
164
165 module IHATEARMSHIFT(
166         input [31:0] insn,
167         input [31:0] operand,
168         input [31:0] reg_amt,
169         input cflag_in,
170         output [31:0] res,
171         output cflag_out
172 );
173         wire [1:0] shift_type;
174         wire [5:0] shift_amt;
175         wire elanus;
176
177         shift_type = insn[6:5];
178         if(insn[4]) begin
179                 shift_amt = {|reg_amt[7:5], reg_amt[4:0]};
180                 elanus = 1'b1;
181         end else begin
182                 shift_amt = {insn[11:7] == 5'b0, insn[11:7]};
183                 elanus = 1'b0;
184         end
185
186         /* might want to write our own damn shifter that does arithmetic/logical efficiently and stuff */
187         always @ (*) begin
188                 case (shift_type)
189                 `SHIFT_LSL: begin
190                         {cflag_out, res} = {cflag_in, operand} << {elanus & shift_amt[5], shift_amt[4:0]};
191                 end
192                 `SHIFT_LSR: begin
193                         {res, cflag_out} = {operand, cflag_in} >> shift_amt;
194                 end
195                 `SHIFT_ASR: begin
196                         {res, cflag_out} = {operand, cflag_in} >> shift_amt | (operand[31] ? ~(33'h1FFFFFFFF >> shift_amt) : 33'b0);
197                 end
198                 `SHIFT_ROR: begin
199                         if(!elanus && shift_amt[4:0] == 5'b0) begin /* RRX x.x */
200                                 res = {cflag_in, operand[31:1]};
201                                 cflag_out = operand[0];
202                         end else if(!shift_amt) begin
203                                 res = operand;
204                                 cflag_out = cflag_in;
205                         end else begin
206                                 res = operand >> shift_amt[4:0] | operand << (5'b0 - shift_amt[4:0]);
207                                 cflag_out = operand[shift_amt[4:0] - 5'b1];
208                         end
209                 end
210         end
211 endmodule
This page took 0.03119 seconds and 4 git commands to generate.