OpenCores
URL https://opencores.org/ocsvn/m65c02/m65c02/trunk

Subversion Repositories m65c02

[/] [m65c02/] [trunk/] [Src/] [RTL/] [M65C02_ALU.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 MichaelA
///////////////////////////////////////////////////////////////////////////////
2
//
3
//  Copyright 2009-2013 by Michael A. Morris, dba M. A. Morris & Associates
4
//
5
//  All rights reserved. The source code contained herein is publicly released
6
//  under the terms and conditions of the GNU Lesser Public License. No part of
7
//  this source code may be reproduced or transmitted in any form or by any
8
//  means, electronic or mechanical, including photocopying, recording, or any
9
//  information storage and retrieval system in violation of the license under
10
//  which the source code is released.
11
//
12
//  The source code contained herein is free; it may be redistributed and/or 
13
//  modified in accordance with the terms of the GNU Lesser General Public
14
//  License as published by the Free Software Foundation; either version 2.1 of
15
//  the GNU Lesser General Public License, or any later version.
16
//
17
//  The source code contained herein is freely released WITHOUT ANY WARRANTY;
18
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
19
//  PARTICULAR PURPOSE. (Refer to the GNU Lesser General Public License for
20
//  more details.)
21
//
22
//  A copy of the GNU Lesser General Public License should have been received
23
//  along with the source code contained herein; if not, a copy can be obtained
24
//  by writing to:
25
//
26
//  Free Software Foundation, Inc.
27
//  51 Franklin Street, Fifth Floor
28
//  Boston, MA  02110-1301 USA
29
//
30
//  Further, no use of this source code is permitted in any form or means
31
//  without inclusion of this banner prominently in any derived works. 
32
//
33
//  Michael A. Morris
34
//  Huntsville, AL
35
//
36
///////////////////////////////////////////////////////////////////////////////
37
 
38
`timescale 1ns / 1ps
39
 
40
///////////////////////////////////////////////////////////////////////////////
41
// Company:         M. A. Morris & Associates 
42
// Engineer:        Michael A. Morris
43
// 
44
// Create Date:     07:00:31 11/25/2009 
45
// Design Name:     WDC W65C02 Microprocessor Re-Implementation
46
// Module Name:     M65C02_ALU 
47
// Project Name:    C:\XProjects\ISE10.1i\MAM6502 
48
// Target Devices:  Generic SRAM-based FPGA 
49
// Tool versions:   Xilinx ISE10.1i SP3
50
// 
51
// Description:
52
//
53
//  This module implements the ALU for the M65C02 microprocessor. Included in
54
//  the ALU are the accumulator (A), pre/post-index registers (X and Y), stack
55
//  pointer (S), and processor status word (P). The microcode, composed of a
56
//  fixed part from the instruction decoder (IDEC) and a variable portion from
57
//  the execution engine, are used to control a binary adder unit (AU), a BCD
58
//  adder unit (DU), a shift unit (SU), a logic unit (LU) and a bit unit (BU).
59
//  The AU performs binary two's complement addition, and the DU performs un-
60
//  signed BCD addition on two operands. These units also handle subtraction,
61
//  but the operand multiplexers feeding data into these units must perform the
62
//  required complement of the operand to subtract from the accumulator. The SU
63
//  performs arithmetic and logical shifts and rotate operations on an operand.
64
//  The LU performs bit-wise operations (OR, AND, and XOR) on one operand. The
65
//  BU performs bit masking and testing on one operand.
66
//
67
//  The ALU requires an En input to be asserted to initiate the operation that
68
//  the fixed IDEC microword requires. The SC and Done fields in the variable
69
//  microwords from the execution engine controls the En input to the ALU. The
70
//  En input is a registered signal which when asserted indicates that the ope-
71
//  rands required to complete an operation have been read from memory. The
72
//  addressing mode of the instruction will determine when En is asserted. In
73
//  the case of program flow control instructions, En and the StkOp field will
74
//  control the updates to the stack pointer, S. In the case of non-program
75
//  flow control instructions, En alone controls the updates to these regis-
76
//  ters: A, X, Y, P. For implicit or accumulator mode instructions, En is ge-
77
//  nerally asserted when the opcode is loaded into the Instruction Register
78
//  (IR). Otherwise, it is asserted when the memory operand is loaded into the
79
//  OP1 register, and the operation defined by IDEC should be completed with
80
//  the available data. 
81
//
82
//  The Op input selects the operation to be performed by the AU, SU, or LU.
83
//      Note: Q = {Y, X, M, A}, R = {8'h01, M}, Ci = (CSel ? Sub : C).
84
//  
85
//   Op   Mnemonic     Operation              Condition Code
86
//  0000     XFR     ALU <= {OSel: 0, A, X, Y, P, S, M}
87
//  0001     OR      ALU <= A | M;      N <= ALU[7]; Z <= ~|ALU;
88
//  0010     AND     ALU <= A & M;      N <= ALU[7]; Z <= ~|ALU;
89
//  0011     EOR     ALU <= A ^ M;      N <= ALU[7]; Z <= ~|ALU;
90
//  0100     ADC     ALU <= Q +  M + C; N <= ALU[7]; Z <= ~|ALU;
91
//                                      V <= OVF;    C <= COut;
92
//  0101     SBC     ALU <= Q + ~M + C; N <= ALU[7]; Z <= ~|ALU;
93
//                                      V <= OVF;    C <= COut;
94
//  0110     INC     ALU <= Q +  1 + 0; N <= ALU[7]; Z <= ~|ALU;
95
//  0111     DEC     ALU <= Q + ~1 + 1; N <= ALU[7]; Z <= ~|ALU;
96
//  1000     ASL     ALU <= R << 1;     N <= ALU[7]; Z <= ~|ALU; C <= R[7];
97
//  1001     LSR     ALU <= R >> 1;     N <= ALU[7]; Z <= ~|ALU; C <= R[0];
98
//  1010     ROL     ALU <= {R[6:0], C} N <= ALU[7]; Z <= ~|ALU; C <= R[7];
99
//  1011     ROR     ALU <= {C, R[7:1]} N <= ALU[7]; Z <= ~|ALU; C <= R[0];
100
//  1100     BIT     ALU <= (A & M);    N <= M[7];   Z <= ~|(A & M);
101
//                                      V <= M[6];
102
//  1101     TRB     ALU <= M & ~A;                  Z <= ~|(A & M);
103
//  1110     TSB     ALU <= M |  A;                  Z <= ~|(A & M);
104
//  1111     CMP     ALU <= Q + ~M + 1  N <= ALU[7]; Z <= ~|ALU; C <= COut;
105
//
106
//  Although the condition codes modified by the ALU are shown above, the CC
107
//  input field will actually control loading condition codes into P register.
108
//  This is especially true for the N and V condition codes with respect to the
109
//  BIT instruction. N and V are modified by BIT as indicated above, except for
110
//  for the BIT #imm instruction which only modifies Z, and leaves N and V un-
111
//  changed like the TRB and TSB instructions.
112
//
113
//  The coding for the WSel and OSel fields follows:
114
//        3     3
115
//  Sel  WSel  OSel
116
//  000  none   M
117
//  001   A     A
118
//  010   X     X
119
//  011   Y     Y
120
//  100   -     0
121
//  101   S     S
122
//  110   P     P
123
//  111   M     M
124
//
125
//  The WSel field provides the register enable for writing into a register,
126
//  and the OSel field determines the value of the ALU result bus. Typically
127
//  the ALU result bus is the ALU. But on the occasion of a load, store, xfer,
128
//  push, and pull instructions, the ALU bus is driven by 0, A, X, Y, S, P, and
129
//  M. In this manner, the ALU result can be either loaded into the register
130
//  designated by the WSel field, or it can be written to memory.
131
//
132
//  The stack pointer, S, is also controlled directly by the execution SM. The
133
//  execution engine provides the operation of the stack pointer for push and
134
//  pop operations. The stack pointer and the two index registers are provided
135
//  to the Memory Address Register address generator. The value of the stack
136
//  output to the address generator is controlled by StkOp input field.
137
//
138
//  The coding of these control fields and the ALU field is designed to yield a
139
//  0 at the output of the module if all the input control fields are logical
140
//  0. This means that a NOP is simply a zero for all ALU control fields.
141
//
142
//  The CC_Sel field controls the CC_Out condition code test signal and the 
143
//  updating of the individual bits in P in response to specific instructions:
144
//
145
//  00_xxx: NOP/TRUE    - CC_Out =  1 unless (CCSel[4:3] != 2'b01)
146
//  01_000: CC          - CC_Out = ~C;
147
//  01_001: CS          - CC_Out =  C;
148
//  01_010: NE          - CC_Out = ~Z;
149
//  01_011: EQ          - CC_Out =  Z;
150
//  01_100: VC          - CC_Out = ~V;
151
//  01_101: VS          - CC_Out =  V;
152
//  01_110: PL          - CC_OUT = ~N;
153
//  01_111: MI          - CC_Out =  N;
154
//  10_000: CLC         - C <= 0;
155
//  10_001: SEC         - C <= 1;
156
//  10_010: CLI         - I <= 0;
157
//  10_011: SEI         - I <= 1;
158
//  10_100: CLD         - D <= 0;
159
//  10_101: SED         - D <= 1;
160
//  10_110: CLV         - V <= 0;
161
//  10_111: BRK         - B <= 1;
162
//  11_000: Z           - Z <= ~|(A & M);
163
//  11_001: NZ          - N <= ALU[7]; Z <= ~|ALU;
164
//  11_010: NZC         - N <= ALU[7]; Z <= ~|ALU; C <= COut
165
//  11_011: NVZ         - N <= M[7];   Z <= ~|(A & M); V <= M[6]; 
166
//  11_100: NVZC        - N <= ALU[7]; Z <= ~|ALU; V <= OVF;  C <= COut;
167
//  11_101: Rsvd
168
//  11_110: Rsvd
169
//  11_111: Rsvd        - P <= M;
170
//
171
//  The stack operations supported are: hold, rsvd, ++S, and S--. The stack
172
//  pointer can only be loaded from the X index register. Similarly, the stack
173
//  pointer can only be transfered to the X index register. The stack pointer
174
//  points to an open location on the stack. Thus, push operations write the
175
//  value at the location pointed to by S, and post-decrements S, S--. Stack 
176
//  pull operations require the value to be incremented by one, ++S, before
177
//  that location can be read into OP1 and subsequently written to one of four 
178
//  registers: P, A, X, or Y.
179
//
180
//  The stack pointer control, StkOp, field is generated by the execution
181
//  engine:
182
//
183
//  00  :   Hold;
184
//  01  :   Rsvd;
185
//  10  :   S--;
186
//  11  :   ++S;
187
//
188
// Dependencies:    M65C02_Bin.v, M65C02_BCD.v
189
//
190
// Revision:
191
// 
192
//  0.01    09K25   MAM     Initial coding
193
//
194
//  0.02    09K30   MAM     Corrected coding for zero detection from ~|ALU to
195
//                          ~|ALU[7:0]. ALU[8] is Carry Out, and first formu-
196
//                          lation only correct for non-arithmetic, non-shift
197
//                          operations. Corrected binary mode OVF equation.
198
//                          Changed priority of write enables for the PSW bits
199
//                          making the register write the highest priority,
200
//                          followed by the SEx and CLx instructions, respec-
201
//                          tively, followed by any special modes, and at the
202
//                          lowest priority any CC updates of ALU instructions.
203
//
204
//  0.03    09K30   MAM     Modified ALU structure to explicitly define the
205
//                          width of all operations. All operations explicitly
206
//                          set at 9 bits. Apparently, the synthesizer is able
207
//                          to better resolve the specified operations into 
208
//                          FPGA primitives. Nearly 11% improvement in the 
209
//                          reported speed of the synthesized ckts as a result.
210
//                          Also reported significant reduction in the reported
211
//                          area of the ckts. From an area of 35 to an area of
212
//                          23, which is a 33% reduction in the area of the
213
//                          synthesized ckts.
214
//
215
//  0.04    09L01   MAM     Broke the ADC/SBC adders into an 8-bit segment and
216
//                          a 1-bit segment in order to determine the carries
217
//                          out of bit 6 and out of bit 7 independently. This
218
//                          allows 2's Complement Overflow to be determined as
219
//                          exclusive OR of these two carries: V <= ^{C[7:6]}.
220
//                          Setting V with the sign of the two inputs and Sum,
221
//                          V = (A[7] & M[7] & ~S[7]) | (~A[7] & ~M[7] & S[7]),
222
//                          was proving to be wrong for the three operand ADDs
223
//                          that these two instructions actually represent. The
224
//                          overflow detection mechanism is independent of the
225
//                          number of operands into the adder tree. There was 
226
//                          an additional 10% improvement in speed as a result
227
//                          of this approach to ADC/SBC.
228
//
229
//  0.05    09L25   MAM     Modified the input parameter list to include select
230
//                          signals for the input of the adder. Two ports were
231
//                          defined for the Binary/BCD adder: Q and R. Selects
232
//                          were added to select the Q and R operands for the
233
//                          various instructions that utilize the adder: ADC,
234
//                          SBC, INC, DEC, and CMP. Also included BCD mode for
235
//                          this adder. Including the BCD mode slows down the
236
//                          ALU.
237
//
238
//  0.06    09L31   MAM     Modified the module to separate the multiplexer and
239
//                          the various computational units comprising the ALU.
240
//                          Registered versions of the Logic Unit (LU) (ORA, 
241
//                          AND, EOR), the Arithmetic Unit (AU) (ADC, SBC, INC,
242
//                          DEC, CMP), the Shift Unit (SU) (ASL, LSR, ROL, ROR)
243
//                          and the Bit Unit (BU) (BIT, TSB, TRB) were created.
244
//                          The multiplexer was modified as a registered device
245
//                          and implements the computation unit result multi-
246
//                          plexer and the ALU register multiplexer. Implemen-
247
//                          ted a Register Write Enable and global Valid signal
248
//                          generator to deal with the apropriate register up-
249
//                          dates. Modified the stack address generation logic
250
//                          to accomodate the registered nature of the ALU.
251
//
252
//  1.00    11D09   MAM     Removed unused code previously commented out.
253
//
254
//  1.01    11E14   MAM     Corrected the comments regarding Q and R operand
255
//                          multiplexer encoding.
256
//
257
//  1.02    12A28   MAM     Added parameter to set default value of Stack Ptr
258
//                          after reset.
259
//
260
//  1.10    12B04   MAM     Removed pipeline registers from the ALU Valid and
261
//                          StkPtr signals. Also, separated the LST (Load/Store
262
//                          /Transfer) mux from the ALU mux for readability.
263
//
264
//  1.11    12B11   MAM     Adjusted the Shift Unit's implementation to use a
265
//                          common structure that clearly shows the bit being
266
//                          being moved into the C, and similarly, the bit vec-
267
//                          tor being assigned to the ALU bus. Corrected com-
268
//                          ment on U multiplexer of the Q bus. The X and Y 
269
//                          register operations listed were swapped.
270
//
271
//  1.20    12B18   MAM     Added FF to delay SetB by one cycle. This delayed
272
//                          signal clears the D flag and sets the I flag on the
273
//                          cycle after the PSW is pushed onto the stack during
274
//                          a BRK instruction. Also added an input, ISR, that
275
//                          is asserted by the interrupt processing logic after
276
//                          pushing the PSW so that D is cleared and I is set.
277
//                          In both cases, the interrupt service routines will
278
//                          operate in binary mode and with external maskable
279
//                          interrupts disabled.
280
//
281
//  1.21    12B19   MAM     Renamed module: MAM6502_ALU => M65C02_ALU.
282
//
283
//  1.30    12B20   MAM     Removed FF added by 1.20. Decided that ISR strobe,
284
//                          controlled by the microcode, was a better control
285
//                          signal for this purpose. ISR expected to be assert-
286
//                          ed by interrupt and break microroutines at the cor-
287
//                          rect time before the start of the first instruction
288
//                          of the interrupt/trap service routine. Since the
289
//                          first instruction after accepting the interrupt or
290
//                          executing BRK is always executed, the D and I flags
291
//                          do not need to be modified until the end of that
292
//                          instruction.
293
//
294
//                          Substantially changed the Reg_WE logic and PSW im-
295
//                          plementation. During RTI testing, two problems were
296
//                          found and corrected: (1) control of register write
297
//                          enables was not possible, and (2) updates to the P
298
//                          were occuring unexpectedly in some situations. To
299
//                          correct the first, the microcode was changed and a
300
//                          port was added that provided a 3-bit register write
301
//                          enable input. This 3-bit input is combined with the
302
//                          3-bit WSel field from the fixed microword, to gene-
303
//                          rate register write enables for A, X, Y, S, and P.
304
//                          This new structure appears to retain the desired
305
//                          speed, and it is easier to control the desired ac-
306
//                          tions using the microprogram.
307
//
308
//                          To correct the second required modifications to P
309
//                          register. In putting in those changes, it was appa-
310
//                          rent that the use of individual registers and muxes
311
//                          for the various input signals, was a major contri-
312
//                          butor to poor implementation. Thus, a single 7-bit
313
//                          register was implemented, with an input multiplexer
314
//                          the more clearly defines the input signals and data
315
//                          sources for each type of operation that changes the
316
//                          PSW at an idividual bit level or as whole.
317
//
318
//                          The changes made in these two areas allow PAR to
319
//                          satisfy the 100 MHz operating speed objective.
320
//
321
//  1.31    12B23   MAM     Delete commented out code. Changed WE_x equation to
322
//                          use Valid instead of En. Valid will be delayed by 
323
//                          one cycle for BDC mode ADC/SBC instructions. This
324
//                          is expected to correctly write the BCD result into
325
//                          A and the flags into P. Without switching to Valid,
326
//                          the BCD result would not be captured correctly into
327
//                          A or P. Kept En as part of the WE_S equation, the
328
//                          component of the equation used for inc/dec of the
329
//                          stack pointer during stack operations.
330
//
331
//  1.32    12B24   MAM     Modified the port list to add a ready port, Rdy.
332
//                          Previosly the core-level signal was applied to the
333
//                          ALU through the En input. Separating out Rdy allows
334
//                          a combinatorial logic loop to be broken. Rdy is now
335
//                          applied to the write enable signals. The En input
336
//                          drives the ALU functional units, which drive Valid
337
//                          in the same cycle, or in the following cycle. In
338
//                          the case that Valid is delayed one cycle, Rdy will
339
//                          be deasserted by the core-level circuit, and the
340
//                          cycle will be stretched. When Valid asserts, Rdy 
341
//                          will also assert, the registers will be written,
342
//                          and the cycle will continue. This cycle stretch
343
//                          will only occur for BCD mode ADC/SBC instructions.
344
//
345
//  1.40    12B25   MAM     Made a correction to the PSW. Further research into
346
//                          the operation of the PSW indicates that there are
347
//                          only 6 physical bits in the register itself. Bit 4
348
//                          in P, the programmer visible status word, is gener-
349
//                          ally described as the B, or Break flag. Research 
350
//                          indicates that this bit is not implemented as a
351
//                          FF. Instead, the BRK instruction forces this bit to
352
//                          logic 1 during the push of P to the stack. It only
353
//                          exists in the copy of the PSW on the stack. It is
354
//                          this behavior that requires a shared vector inter-
355
//                          rupt service routine to examine the stack version
356
//                          of the PSW to determine if the interrupt is a re-
357
//                          sult of an external IRQ or a BRK instruction. Also
358
//                          applied this behavior of the B bit to PHP instruc-
359
//                          tion. The number of FFs used to implement PSW has
360
//                          been decreased by 1, and the declaration of B has
361
//                          been removed from the source.
362
//
363
//  1.50    12K12   MAM     Modified the stack pointer logic to eliminate extra
364
//                          adder.
365
//
366
//  1.60    12K20   MAM     During multi-cycle microcycle, the interrupt handler
367
//                          was found to be modifying the PSW early. This means
368
//                          that the D and I flags were not properly pushed onto
369
//                          the stack. The modified versions of the two flags
370
//                          were pushed onto the stack instead of the values in
371
//                          the PSW at the start of the interrupt handler. Fixed
372
//                          by qaulifying the PSW modification with the Rdy sig-
373
//                          nal which signifies the end of a microcycle. Worked
374
//                          with single cycle microcycles, including BCD ops,
375
//                          because Rdy is asserted and/or the BCD op completes
376
//                          during the push PCH cycle. With a multi-cycle micro-
377
//                          cycle, the modification occurred one cycle after the
378
//                          push PSW microcycle, but before the data was written
379
//                          to the stack. Hence, qualifying it with Rdy, delays
380
//                          the modification until the first cycle of the next
381
//                          microcycle; the original intent.
382
//
383
//  2.00    12L11   MAM     Added the Rockwell instructions (RMBx, SMBx, BBRx,
384
//                          and BBSx) to the ALU. Modified the Bit Logical Unit
385
//                          to accept a new command and bit mask input. The new
386
//                          commands use four unused CCSel codes, and a mask
387
//                          provided by a new input port connected to the Decode
388
//                          ROM. All other changes expected to be made in the 
389
//                          microprogram. RMBx/SMBx can use the RMW_DP micro-
390
//                          routine, but BBRx/BBSx require a new microroutine.
391
//
392
//  3.00    13H04           Made the internal bus multiplexers into a one-hot
393
//                          decoded OR bus. Had to make some minor adjustments
394
//                          to the LST_En and En_RU signals to accomodate the
395
//                          changes in the bus multiplexer implementation.
396
//
397
// Additional Comments:
398
//
399
///////////////////////////////////////////////////////////////////////////////
400
 
401
module M65C02_ALU #(
402
    parameter pStkPtr_Rst = 0  // Stack Pointer Value after Reset
403
)(
404
    input   Rst,            // System Reset - synchronous reset 
405
    input   Clk,            // System Clock
406
 
407
    input   Rdy,            // Ready
408
 
409
    input   En,             // Enable - ALU functions
410
    input   [2:0] Reg_WE,   // Register Write Enable 
411
    input   ISR,            // Asserted on entry to Interrupt Service Routine 
412
 
413
    //  ALU Ports
414
 
415
    input   [3:0] Op,       // ALU Operation Select
416
    input   [1:0] QSel,     // ALU Q Bus Multiplexer Select
417
    input   RSel,           // ALU R Bus Multiplexer Select
418
    input   Sub,            // ALU Adder Operation Select
419
    input   CSel,           // ALU Carry In Multiplexer Select
420
    input   [2:0] WSel,     // ALU Register WE Select
421
    input   [2:0] OSel,     // ALU Output Multiplexer Select
422
    input   [4:0] CCSel,    // ALU Condition Code Operation Select
423
    input   [7:0] Msk,      // ALU Mask for Rockwell Instructions
424
 
425
    input   [7:0] M,        // ALU Memory Operand Input
426
    output  reg [7:0] Out,  // ALU Output(asynchronous)
427
    output  Valid,          // ALU Output Valid
428
 
429
    output  reg CC_Out,     // Condition Code Test Output
430
 
431
    //  Stack Pointer Output
432
 
433
    input   [1:0] StkOp,    // Stack Pointer Operation Select
434
 
435
    output  [7:0] StkPtr,   // Stack Pointer Output: {S, S+1}
436
 
437
    //  Internal Processor Registers
438
 
439
    output  reg [7:0] A,    // Accumulator
440
    output  reg [7:0] X,    // X Index Register
441
    output  reg [7:0] Y,    // Y Index Register
442
    output  reg [7:0] S,    // Stack Pointer
443
 
444
    output  [7:0] P         // Processor Status Word
445
);
446
 
447
///////////////////////////////////////////////////////////////////////////////
448
//
449
//  Local Parameter Decalarations
450
//
451
 
452
//  Op[3:0] Encodings
453
 
454
//  Logic Unit
455
localparam pALU_NOP = 0;    // NOP - No Operation: ALU<={OSel: M,A,X,Y,Z,P,S,M}
456
localparam pALU_AND = 1;    // AND - bitwise AND Accumulator with Memory
457
localparam pALU_ORA = 2;    // ORA - bitwise OR Accumulator with Memory
458
localparam pALU_EOR = 3;    // EOR - bitwise XOR Accumulator with Memory
459
//  Arithmetic Unit
460
localparam pALU_ADC = 4;    // ADC - Add  Memory to Accumulator + Carry
461
localparam pALU_SBC = 5;    // SBC - Add ~Memory to Accumulator + Carry (Sub)
462
localparam pALU_INC = 6;    // INC - Increment {A, X, Y, or M} (binary-only)
463
localparam pALU_DEC = 7;    // DEC - Decrement {A, X, Y, or M} (binary-only)
464
//  Shift Unit
465
localparam pALU_ASL = 8;    // ASL - Arithmetic Shift Left {A, or M}
466
localparam pALU_LSR = 9;    // LSR - Logical Shift Right {A, or M}
467
localparam pALU_ROL = 10;   // ROL - Rotate Left through Carry {A, or M}
468
localparam pALU_ROR = 11;   // ROR - Rotate Right through Carry {A, or M}
469
//  Bit Unit
470
localparam pALU_BIT = 12;   // BIT - Test Memory with Bit Mask in Accumulator
471
localparam pALU_TRB = 13;   // TRB - Test and Reset Memory with Bit Mask in A
472
localparam pALU_TSB = 14;   // TSB - Test and Set Memory with Bit Mask in A
473
//  Compare Unit
474
localparam pALU_CMP = 15;   // CMP - Compare Memory to Accumulator (binary-only)
475
 
476
//  WSel/OSel Register Select Field Codes
477
 
478
localparam pSel_A   = 1;    // Select Accumulator
479
localparam pSel_X   = 2;    // Select X Index
480
localparam pSel_Y   = 3;    // Select Y Index
481
localparam pSel_Z   = 4;    // Select Zero
482
localparam pSel_S   = 5;    // Select Stack Pointer
483
localparam pSel_P   = 6;    // Select PSW
484
localparam pSel_M   = 7;    // Select Memory Operand
485
 
486
//  Condition Code Select
487
 
488
localparam pSMB  = 4;       // Set Memory Bit
489
localparam pRMB  = 5;       // Reset Memory Bit
490
localparam pBBS  = 6;       // Branch if Memory Bit Set
491
localparam pBBR  = 7;       // Branch if Mmemory Bit Reset
492
//
493
localparam pCC   = 8;       // Carry Clear
494
localparam pCS   = 9;       // Carry Set
495
localparam pNE   = 10;      // Not Equal to Zero
496
localparam pEQ   = 11;      // Equal to Zero
497
localparam pVC   = 12;      // Overflow Clear
498
localparam pVS   = 13;      // Overflow Set
499
localparam pPL   = 14;      // Plus (Not Negative)
500
localparam pMI   = 15;      // Negative
501
localparam pCLC  = 16;      // Clear C
502
localparam pSEC  = 17;      // Set Carry
503
localparam pCLI  = 18;      // Clear Interrupt mask
504
localparam pSEI  = 19;      // Set Interrupt mask
505
localparam pCLD  = 20;      // Clear Decimal mode
506
localparam pSED  = 21;      // Set Decimal mode
507
localparam pCLV  = 22;      // Clear Overflow
508
localparam pBRK  = 23;      // Set BRK flag
509
localparam pZ    = 24;      // Set Z = ~|(A & M)
510
localparam pNZ   = 25;      // Set N and Z flags from ALU
511
localparam pNZC  = 26;      // Set N, Z, and C flags from ALU
512
localparam pNVZ  = 27;      // Set N and V flags from M[7:6], and Z = ~|(A & M)
513
localparam pNVZC = 28;      // Set N, V, Z, and C from ALU
514
//
515
//
516
localparam pPSW  = 31;      // Set P from ALU
517
 
518
///////////////////////////////////////////////////////////////////////////////
519
//
520
//  Declarations
521
//
522
 
523
reg     COut;                   // Carry Out -> input to C
524
reg     [5:0] PSW;              // Processor Status Word (Register)
525
wire    N, V, D, I, Z, C;       // Individual, Registered Bits in PSW
526
 
527
wire    [7:0] W, U, Q;          // Adder Input Busses
528
wire    [7:0] T, R;
529
wire    Ci;                     // Adder Carry In signal
530
 
531
//  ALU Component Output Busses
532
 
533
reg     [8:0] LU;               // Logic Unit Output
534
reg     LU_Valid;               // LU Output Valid
535
wire    [8:0] AU;               // Adder Unit Output
536
wire    AU_Valid;               // AU Output Valid
537
wire    [8:0] DU;               // Decimal (BCD) Unit Output
538
wire    DU_Valid;               // DU Output Valid
539
reg     [8:0] SU;               // Shift/Rotate Unit Output
540
reg     SU_Valid;               // SU Output Valid
541
reg     [8:0] BU;               // Bit Unit Output
542
reg     BU_Valid;               // BU Output Valid
543
 
544
reg     [8:0] RU;               // Rockwell Unit Output
545
reg     RU_Valid;               // RU Output Valid
546
 
547
wire    LST_En;                 // Load/Store/Transfer Enable
548
reg     [5:0] LST_Sel;          // Load/Store/Transfer Select ROM
549
reg     [8:0] LST;              // Load/Store/Transfer Output Multiplexer
550
 
551
reg     SelA, SelX, SelY, SelS, SelP;   // Decoded Register Write Selects
552
 
553
wire    OV;                     // Arithmetic Unit Overflow Flag
554
 
555
///////////////////////////////////////////////////////////////////////////////
556
//
557
//  Implementation
558
//
559
 
560
// Q Multiplexer
561
 
562
assign W = ((QSel[0]) ? M : A);     // ? INC M/DEC M : Default
563
assign U = ((QSel[0]) ? Y : X);     // ? INY/DEY/CPY : INX/DEX/CPX
564
assign Q = ((QSel[1]) ? U : W);
565
 
566
// R Multiplexer
567
 
568
assign T = ((RSel) ? 8'h01 : M);    // ? INC/DEC     : ADC/SBC/CMP (default)
569
assign R = ((Sub)  ? ~T    : T);    // ? SBC/DEC/CMP : ADC/INC (default)
570
 
571
// Carry In Multiplexer
572
 
573
assign Ci = ((CSel) ? Sub : C);     // ? INC/DEC/CMP : ADC/SBC (default)
574
 
575
//  M65C02 Logic, Arithmetic, Shift, and Bit Unit Implementations
576
 
577
// Logic Unit Implementation
578
 
579
assign En_LU = (En & (Op[3:2] == 2'b00) & |Op[1:0]);
580
 
581
always @(*)
582
begin
583
    if(En_LU)
584
        case(Op[1:0])
585
            2'b01   : LU <= {1'b0, A & M};           // AND
586
            2'b10   : LU <= {1'b0, A | M};           // ORA
587
            default : LU <= {1'b0, A ^ M};           // EOR
588
        endcase
589
    else
590
        LU <= 0;
591
end
592
 
593
always @(*)
594
begin
595
    LU_Valid <= En_LU;
596
end
597
 
598
//  Binary Adder Unit Implementation (INC/INX/INY/DEC/DEX/DEY/CMP, ADC/SBC)
599
 
600
assign En_AU = (  (En & (  (Op == pALU_ADC) | (Op == pALU_SBC)) & ~D)
601
                | (En & (  (Op == pALU_INC)
602
                         | (Op == pALU_DEC)
603
                         | (Op == pALU_CMP))));
604
 
605
M65C02_BIN  BIN (
606
                .En(En_AU),
607
                .A(Q),
608
                .B(R),
609
                .Ci(Ci),
610
                .Out(AU),
611
                .OV(OV_AU),
612
                .Valid(AU_Valid)
613
            );
614
 
615
//  Decimal (BCD) Adder Unit Implementation (ADC/SBC (Decimal-Only))
616
 
617
assign En_DU = (En & ((Op == pALU_ADC) | (Op == pALU_SBC)) & D);
618
 
619
M65C02_BCD  BCD (
620
                .Rst(Rst),
621
                .Clk(Clk),
622
                .En(En_DU),
623
                .Op(Sub),
624
                .A(Q),
625
                .B(R),
626
                .Ci(Ci),
627
                .Out(DU),
628
                .OV(OV_DU),
629
                .Valid(DU_Valid)
630
            );
631
 
632
//  Multiplex Overflow based on the Adder used
633
 
634
assign OV = ((AU_Valid) ? OV_AU : OV_DU);
635
 
636
//  Shift Unit Implementation
637
 
638
assign En_SU = (En & (Op[3:2] == 2'b10));
639
 
640
always @(*)
641
begin
642
    if(En_SU)
643
        case(Op[1:0])
644
            2'b00 : SU <= {W[7], {W[6:0], 1'b0}};   // ASL
645
            2'b01 : SU <= {W[0], {1'b0, W[7:1]}};   // LSR
646
            2'b10 : SU <= {W[7], {W[6:0], C}};      // ROL
647
            2'b11 : SU <= {W[0], {C, W[7:1]}};      // ROR
648
        endcase
649
    else
650
        SU <= 0;
651
end
652
 
653
always @(*)
654
begin
655
    SU_Valid <= En_SU;
656
end
657
 
658
// Bit Unit Implementation
659
 
660
assign En_BU = (En & ((Op[3:2] == 2'b11) & ~(Op == pALU_CMP)));
661
 
662
always @(*)
663
begin
664
    if(En_BU)
665
        case(Op[1:0])
666
            2'b01   : BU <= {1'b0,  ~A & M};    // TRB
667
            2'b10   : BU <= {1'b0,   A | M};    // TSB
668
            default : BU <= {1'b0,   A & M};    // BIT
669
        endcase
670
    else
671
        BU <= 0;
672
end
673
 
674
always @(*)
675
begin
676
    BU_Valid <= En_BU;
677
end
678
 
679
//  Rockwell Unit 
680
//  Capabilities expanded to execute the Rockwell RSBx, SMBx, BBRx, and BBSx
681
//  instructions. The CCSel field is used to select the operation:
682
//      4 - SMBx; 4 - RMBx; 6 = BBSx; 7 - BBRx;
683
//  if(CCSel[4:2] == 1) one of the Rockwell instructions is being executed;
684
//  else a normal 65C02 instruction is being executed;
685
//
686
//  For the Rockwell instructions, the mask is not provided by the accumulator.
687
//  Instead, the mask is provided by least significant 8 bits of the fixed
688
//  microword, which was added as an additional input to the module.
689
 
690
assign En_RU = (CCSel[4:2] == 4'b001);
691
 
692
always @(*)
693
begin
694
    if(En_RU)
695
        case(CCSel[1:0])
696
            2'b00 : RU <= {1'b0, Msk |  M};    // SMBx
697
            2'b01 : RU <= {1'b0, Msk &  M};    // RMBx
698
            2'b10 : RU <= {1'b0, Msk &  M};    // BBSx
699
            2'b11 : RU <= {1'b0, Msk & ~M};    // BBRx
700
        endcase
701
    else
702
        RU <= 0;
703
end
704
 
705
always @(*) RU_Valid <= En_RU;
706
 
707
//  Load/Store/Transfer Enable
708
 
709
assign LST_En = ((Op == pALU_NOP) & ~(CCSel[4:2] == 4'b001));
710
 
711
//  Load/Store/Transfer Multiplexer
712
 
713
always @(*)
714
begin
715
    case(OSel)
716
        3'b000 : LST_Sel <= 6'b000_00_1;          // LDA/PLA/LDX/PLX/LDY/PLY/PLP
717
        3'b001 : LST_Sel <= 6'b100_00_0;          // STA/TAX/TAY/PHA
718
        3'b010 : LST_Sel <= 6'b010_00_0;          // STX/TXA/TXS/PHX
719
        3'b011 : LST_Sel <= 6'b001_00_0;          // STY/TYA/PHY
720
        3'b100 : LST_Sel <= 6'b000_00_0;          // STZ
721
        3'b101 : LST_Sel <= 6'b000_10_0;          // TSX
722
        3'b110 : LST_Sel <= 6'b000_01_0;          // PHP
723
        3'b111 : LST_Sel <= 6'b000_00_1;          // LDA/PLA/LDX/PLX/LDY/PLY/PLP
724
    endcase
725
end
726
 
727
always @(*)
728
begin
729
    if(LST_En)
730
        LST <= (  ((LST_Sel[5]) ? {1'b0, A} : 0)  // STA/TAX/TAY/PHA 
731
                | ((LST_Sel[4]) ? {1'b0, X} : 0)  // STX/TXA/TXS/PHX 
732
                | ((LST_Sel[3]) ? {1'b0, Y} : 0)  // STY/TYA/PHY
733
                | ((LST_Sel[2]) ? {1'b0, S} : 0)  // TSX 
734
                | ((LST_Sel[1]) ? {1'b0, P} : 0)  // PHP
735
                | ((LST_Sel[0]) ? {1'b0, M} : 0));// LDA/PLA/LDX/PLX/LDY/PLY/PLP
736
    else
737
        LST <= 0;                                 // STZ
738
end
739
 
740
always @(*) {COut, Out} <= LU | AU | DU | SU | BU | RU | LST;
741
 
742
//  Assign ALU (Result) Valid Output (removed pipeline register 12B04, mam)
743
 
744
assign Valid = |{LU_Valid,
745
                 AU_Valid,
746
                 DU_Valid,
747
                 SU_Valid,
748
                 BU_Valid,
749
                 RU_Valid,
750
                 LST_En   };
751
 
752
//  Condition Code Output
753
 
754
always @(*)
755
begin
756
    case(CCSel)
757
        pBBR    : CC_Out <= |RU;    // Added for Rockwell instructions
758
        pBBS    : CC_Out <= |RU;    // Added for Rockwell instructions
759
        //
760
        pCC     : CC_Out <= ~C;
761
        pCS     : CC_Out <=  C;
762
        pNE     : CC_Out <= ~Z;
763
        pEQ     : CC_Out <=  Z;
764
        pVC     : CC_Out <= ~V;
765
        pVS     : CC_Out <=  V;
766
        pPL     : CC_Out <= ~N;
767
        pMI     : CC_Out <=  N;
768
        default : CC_Out <=  1;
769
    endcase
770
end
771
 
772
///////////////////////////////////////////////////////////////////////////////
773
//  Internal ALU Registers
774
//
775
 
776
//  Decode Register Write Enables
777
 
778
always @(*)
779
begin
780
    casex({Reg_WE, WSel})
781
        6'b001xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b1000_1;
782
        6'b100001   : {SelA, SelX, SelY, SelS, SelP} <= 5'b1000_1;
783
        6'b010xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0100_1;
784
        6'b100010   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0100_1;
785
        6'b011xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0010_1;
786
        6'b100011   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0010_1;
787
        6'b101xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0001_0;
788
        6'b100101   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0001_0;
789
        6'b110xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_1;
790
        6'b100110   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_1;
791
        6'b111xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_1;
792
        6'b100111   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_1;
793
        default     : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_0;
794
    endcase
795
end
796
 
797
///////////////////////////////////////////////////////////////////////////////
798
//
799
//  A - Accumulator
800
//
801
 
802
assign WE_A = SelA & Valid & Rdy;
803
 
804
always @(posedge Clk)
805
begin
806
    if(Rst)
807
        A <= #1 0;
808
    else if(WE_A)
809
        A <= #1 Out;
810
end
811
 
812
///////////////////////////////////////////////////////////////////////////////
813
//
814
//  X - Pre-Index Register
815
//
816
 
817
assign WE_X = SelX & Valid & Rdy;
818
 
819
always @(posedge Clk)
820
begin
821
    if(Rst)
822
        X <= #1 0;
823
    else if(WE_X)
824
        X <= #1 Out;
825
end
826
 
827
///////////////////////////////////////////////////////////////////////////////
828
//
829
//  Y - Post-Index Register
830
//
831
 
832
assign WE_Y = SelY & Valid & Rdy;
833
 
834
always @(posedge Clk)
835
begin
836
    if(Rst)
837
        Y <= #1 0;
838
    else if(WE_Y)
839
        Y <= #1 Out;
840
end
841
 
842
///////////////////////////////////////////////////////////////////////////////
843
//
844
//  P - Processor Status Word: {N, V, 1, B, D, I, Z, C}
845
//
846
 
847
assign WE_P = SelP & Valid & Rdy;
848
 
849
always @(posedge Clk)
850
begin
851
    if(Rst)
852
        PSW <= #1 6'b00_0100;       // I set by default on Rst
853
    else if(ISR & Rdy)
854
        PSW <= #1 {N, V, 1'b0, 1'b1, Z, C};
855
    else if(WE_P)
856
        case(CCSel)
857
            pCLC    : PSW <= #1 {     N,   V,   D,   I,        Z,1'b0};
858
            pSEC    : PSW <= #1 {     N,   V,   D,   I,        Z,1'b1};
859
            pCLI    : PSW <= #1 {     N,   V,   D,1'b0,        Z,   C};
860
            pSEI    : PSW <= #1 {     N,   V,   D,1'b1,        Z,   C};
861
            pCLD    : PSW <= #1 {     N,   V,1'b0,   I,        Z,   C};
862
            pSED    : PSW <= #1 {     N,   V,1'b1,   I,        Z,   C};
863
            pCLV    : PSW <= #1 {     N,1'b0,   D,   I,        Z,   C};
864
            //
865
            pZ      : PSW <= #1 {     N,   V,   D,   I,~|(A & M),   C};
866
            pNZ     : PSW <= #1 {Out[7],   V,   D,   I,    ~|Out,   C};
867
            pNZC    : PSW <= #1 {Out[7],   V,   D,   I,    ~|Out,COut};
868
            pNVZ    : PSW <= #1 {  M[7],M[6],   D,   I,~|(A & M),   C};
869
            pNVZC   : PSW <= #1 {Out[7],  OV,   D,   I,    ~|Out,COut};
870
            pPSW    : PSW <= #1 {Out[7:6], Out[3:0]};
871
            default : PSW <= #1 PSW;
872
        endcase
873
end
874
 
875
//  Decode PSW bits
876
 
877
assign N = PSW[5];  // Negative, nominally Out[7], but M[7] if BIT/TRB/TSB
878
assign V = PSW[4];  // oVerflow, nominally OV,     but M[6] if BIT/TRB/TSB
879
assign D = PSW[3];  // Decimal, set/cleared by SED/CLD, cleared on ISR entry
880
assign I = PSW[2];  // Interrupt Mask, set/cleared by SEI/CLI, set on ISR entry
881
assign Z = PSW[1];  // Zero, nominally ~|Out, but ~|(A&M) if BIT/TRB/TSB
882
assign C = PSW[0];  // Carry, set by ADC/SBC, and ASL/ROL/LSR/ROR instructions
883
 
884
//  Assign PSW bits to P (PSW output port)
885
 
886
assign P = {N, V, 1'b1, ((CCSel == pBRK) | (OSel == pSel_P)), D, I, Z, C};
887
 
888
///////////////////////////////////////////////////////////////////////////////
889
//
890
//  Stack Pointer
891
//
892
 
893
assign Ld_S = Rdy & (SelS & Valid);
894
assign CE_S = Rdy & StkOp[1];
895
 
896
always @(posedge Clk)
897
begin
898
    if(Rst)
899
        S <= #1 pStkPtr_Rst;
900
    else if(Ld_S)
901
        S <= #1 X;                          // TXS
902
    else if(CE_S)
903
        S <= #1 ((StkOp[0]) ? (S + 1)       // Pop
904
                            : (S - 1));     // Push
905
end
906
 
907
//  Assign StkPtr Multiplexer for Push (0) and Pop (1) operation
908
//      Synchronous operation removed, 12B04, mam
909
 
910
assign StkPtr = ((&StkOp) ? (S + 1) : S);   // Stack Addrs to MAR
911
 
912
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.