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

Subversion Repositories m65c02

[/] [m65c02/] [trunk/] [Src/] [RTL/] [M65C02_ALU.v] - Rev 2

Compare with Previous | Blame | View Log

///////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2009-2013 by Michael A. Morris, dba M. A. Morris & Associates
//
//  All rights reserved. The source code contained herein is publicly released
//  under the terms and conditions of the GNU Lesser Public License. No part of
//  this source code may be reproduced or transmitted in any form or by any
//  means, electronic or mechanical, including photocopying, recording, or any
//  information storage and retrieval system in violation of the license under
//  which the source code is released.
//
//  The source code contained herein is free; it may be redistributed and/or 
//  modified in accordance with the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either version 2.1 of
//  the GNU Lesser General Public License, or any later version.
//
//  The source code contained herein is freely released WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
//  PARTICULAR PURPOSE. (Refer to the GNU Lesser General Public License for
//  more details.)
//
//  A copy of the GNU Lesser General Public License should have been received
//  along with the source code contained herein; if not, a copy can be obtained
//  by writing to:
//
//  Free Software Foundation, Inc.
//  51 Franklin Street, Fifth Floor
//  Boston, MA  02110-1301 USA
//
//  Further, no use of this source code is permitted in any form or means
//  without inclusion of this banner prominently in any derived works. 
//
//  Michael A. Morris
//  Huntsville, AL
//
///////////////////////////////////////////////////////////////////////////////
 
`timescale 1ns / 1ps
 
///////////////////////////////////////////////////////////////////////////////
// Company:         M. A. Morris & Associates 
// Engineer:        Michael A. Morris
// 
// Create Date:     07:00:31 11/25/2009 
// Design Name:     WDC W65C02 Microprocessor Re-Implementation
// Module Name:     M65C02_ALU 
// Project Name:    C:\XProjects\ISE10.1i\MAM6502 
// Target Devices:  Generic SRAM-based FPGA 
// Tool versions:   Xilinx ISE10.1i SP3
// 
// Description:
//
//  This module implements the ALU for the M65C02 microprocessor. Included in
//  the ALU are the accumulator (A), pre/post-index registers (X and Y), stack
//  pointer (S), and processor status word (P). The microcode, composed of a
//  fixed part from the instruction decoder (IDEC) and a variable portion from
//  the execution engine, are used to control a binary adder unit (AU), a BCD
//  adder unit (DU), a shift unit (SU), a logic unit (LU) and a bit unit (BU).
//  The AU performs binary two's complement addition, and the DU performs un-
//  signed BCD addition on two operands. These units also handle subtraction,
//  but the operand multiplexers feeding data into these units must perform the
//  required complement of the operand to subtract from the accumulator. The SU
//  performs arithmetic and logical shifts and rotate operations on an operand.
//  The LU performs bit-wise operations (OR, AND, and XOR) on one operand. The
//  BU performs bit masking and testing on one operand.
//
//  The ALU requires an En input to be asserted to initiate the operation that
//  the fixed IDEC microword requires. The SC and Done fields in the variable
//  microwords from the execution engine controls the En input to the ALU. The
//  En input is a registered signal which when asserted indicates that the ope-
//  rands required to complete an operation have been read from memory. The
//  addressing mode of the instruction will determine when En is asserted. In
//  the case of program flow control instructions, En and the StkOp field will
//  control the updates to the stack pointer, S. In the case of non-program
//  flow control instructions, En alone controls the updates to these regis-
//  ters: A, X, Y, P. For implicit or accumulator mode instructions, En is ge-
//  nerally asserted when the opcode is loaded into the Instruction Register
//  (IR). Otherwise, it is asserted when the memory operand is loaded into the
//  OP1 register, and the operation defined by IDEC should be completed with
//  the available data. 
//
//  The Op input selects the operation to be performed by the AU, SU, or LU.
//      Note: Q = {Y, X, M, A}, R = {8'h01, M}, Ci = (CSel ? Sub : C).
//  
//   Op   Mnemonic     Operation              Condition Code
//  0000     XFR     ALU <= {OSel: 0, A, X, Y, P, S, M}
//  0001     OR      ALU <= A | M;      N <= ALU[7]; Z <= ~|ALU;
//  0010     AND     ALU <= A & M;      N <= ALU[7]; Z <= ~|ALU;
//  0011     EOR     ALU <= A ^ M;      N <= ALU[7]; Z <= ~|ALU;
//  0100     ADC     ALU <= Q +  M + C; N <= ALU[7]; Z <= ~|ALU;
//                                      V <= OVF;    C <= COut;
//  0101     SBC     ALU <= Q + ~M + C; N <= ALU[7]; Z <= ~|ALU;
//                                      V <= OVF;    C <= COut;
//  0110     INC     ALU <= Q +  1 + 0; N <= ALU[7]; Z <= ~|ALU;
//  0111     DEC     ALU <= Q + ~1 + 1; N <= ALU[7]; Z <= ~|ALU;
//  1000     ASL     ALU <= R << 1;     N <= ALU[7]; Z <= ~|ALU; C <= R[7];
//  1001     LSR     ALU <= R >> 1;     N <= ALU[7]; Z <= ~|ALU; C <= R[0];
//  1010     ROL     ALU <= {R[6:0], C} N <= ALU[7]; Z <= ~|ALU; C <= R[7];
//  1011     ROR     ALU <= {C, R[7:1]} N <= ALU[7]; Z <= ~|ALU; C <= R[0];
//  1100     BIT     ALU <= (A & M);    N <= M[7];   Z <= ~|(A & M);
//                                      V <= M[6];
//  1101     TRB     ALU <= M & ~A;                  Z <= ~|(A & M);
//  1110     TSB     ALU <= M |  A;                  Z <= ~|(A & M);
//  1111     CMP     ALU <= Q + ~M + 1  N <= ALU[7]; Z <= ~|ALU; C <= COut;
//
//  Although the condition codes modified by the ALU are shown above, the CC
//  input field will actually control loading condition codes into P register.
//  This is especially true for the N and V condition codes with respect to the
//  BIT instruction. N and V are modified by BIT as indicated above, except for
//  for the BIT #imm instruction which only modifies Z, and leaves N and V un-
//  changed like the TRB and TSB instructions.
//
//  The coding for the WSel and OSel fields follows:
//        3     3
//  Sel  WSel  OSel
//  000  none   M
//  001   A     A
//  010   X     X
//  011   Y     Y
//  100   -     0
//  101   S     S
//  110   P     P
//  111   M     M
//
//  The WSel field provides the register enable for writing into a register,
//  and the OSel field determines the value of the ALU result bus. Typically
//  the ALU result bus is the ALU. But on the occasion of a load, store, xfer,
//  push, and pull instructions, the ALU bus is driven by 0, A, X, Y, S, P, and
//  M. In this manner, the ALU result can be either loaded into the register
//  designated by the WSel field, or it can be written to memory.
//
//  The stack pointer, S, is also controlled directly by the execution SM. The
//  execution engine provides the operation of the stack pointer for push and
//  pop operations. The stack pointer and the two index registers are provided
//  to the Memory Address Register address generator. The value of the stack
//  output to the address generator is controlled by StkOp input field.
//
//  The coding of these control fields and the ALU field is designed to yield a
//  0 at the output of the module if all the input control fields are logical
//  0. This means that a NOP is simply a zero for all ALU control fields.
//
//  The CC_Sel field controls the CC_Out condition code test signal and the 
//  updating of the individual bits in P in response to specific instructions:
//
//  00_xxx: NOP/TRUE    - CC_Out =  1 unless (CCSel[4:3] != 2'b01)
//  01_000: CC          - CC_Out = ~C;
//  01_001: CS          - CC_Out =  C;
//  01_010: NE          - CC_Out = ~Z;
//  01_011: EQ          - CC_Out =  Z;
//  01_100: VC          - CC_Out = ~V;
//  01_101: VS          - CC_Out =  V;
//  01_110: PL          - CC_OUT = ~N;
//  01_111: MI          - CC_Out =  N;
//  10_000: CLC         - C <= 0;
//  10_001: SEC         - C <= 1;
//  10_010: CLI         - I <= 0;
//  10_011: SEI         - I <= 1;
//  10_100: CLD         - D <= 0;
//  10_101: SED         - D <= 1;
//  10_110: CLV         - V <= 0;
//  10_111: BRK         - B <= 1;
//  11_000: Z           - Z <= ~|(A & M);
//  11_001: NZ          - N <= ALU[7]; Z <= ~|ALU;
//  11_010: NZC         - N <= ALU[7]; Z <= ~|ALU; C <= COut
//  11_011: NVZ         - N <= M[7];   Z <= ~|(A & M); V <= M[6]; 
//  11_100: NVZC        - N <= ALU[7]; Z <= ~|ALU; V <= OVF;  C <= COut;
//  11_101: Rsvd
//  11_110: Rsvd
//  11_111: Rsvd        - P <= M;
//
//  The stack operations supported are: hold, rsvd, ++S, and S--. The stack
//  pointer can only be loaded from the X index register. Similarly, the stack
//  pointer can only be transfered to the X index register. The stack pointer
//  points to an open location on the stack. Thus, push operations write the
//  value at the location pointed to by S, and post-decrements S, S--. Stack 
//  pull operations require the value to be incremented by one, ++S, before
//  that location can be read into OP1 and subsequently written to one of four 
//  registers: P, A, X, or Y.
//
//  The stack pointer control, StkOp, field is generated by the execution
//  engine:
//
//  00  :   Hold;
//  01  :   Rsvd;
//  10  :   S--;
//  11  :   ++S;
//
// Dependencies:    M65C02_Bin.v, M65C02_BCD.v
//
// Revision:
// 
//  0.01    09K25   MAM     Initial coding
//
//  0.02    09K30   MAM     Corrected coding for zero detection from ~|ALU to
//                          ~|ALU[7:0]. ALU[8] is Carry Out, and first formu-
//                          lation only correct for non-arithmetic, non-shift
//                          operations. Corrected binary mode OVF equation.
//                          Changed priority of write enables for the PSW bits
//                          making the register write the highest priority,
//                          followed by the SEx and CLx instructions, respec-
//                          tively, followed by any special modes, and at the
//                          lowest priority any CC updates of ALU instructions.
//
//  0.03    09K30   MAM     Modified ALU structure to explicitly define the
//                          width of all operations. All operations explicitly
//                          set at 9 bits. Apparently, the synthesizer is able
//                          to better resolve the specified operations into 
//                          FPGA primitives. Nearly 11% improvement in the 
//                          reported speed of the synthesized ckts as a result.
//                          Also reported significant reduction in the reported
//                          area of the ckts. From an area of 35 to an area of
//                          23, which is a 33% reduction in the area of the
//                          synthesized ckts.
//
//  0.04    09L01   MAM     Broke the ADC/SBC adders into an 8-bit segment and
//                          a 1-bit segment in order to determine the carries
//                          out of bit 6 and out of bit 7 independently. This
//                          allows 2's Complement Overflow to be determined as
//                          exclusive OR of these two carries: V <= ^{C[7:6]}.
//                          Setting V with the sign of the two inputs and Sum,
//                          V = (A[7] & M[7] & ~S[7]) | (~A[7] & ~M[7] & S[7]),
//                          was proving to be wrong for the three operand ADDs
//                          that these two instructions actually represent. The
//                          overflow detection mechanism is independent of the
//                          number of operands into the adder tree. There was 
//                          an additional 10% improvement in speed as a result
//                          of this approach to ADC/SBC.
//
//  0.05    09L25   MAM     Modified the input parameter list to include select
//                          signals for the input of the adder. Two ports were
//                          defined for the Binary/BCD adder: Q and R. Selects
//                          were added to select the Q and R operands for the
//                          various instructions that utilize the adder: ADC,
//                          SBC, INC, DEC, and CMP. Also included BCD mode for
//                          this adder. Including the BCD mode slows down the
//                          ALU.
//
//  0.06    09L31   MAM     Modified the module to separate the multiplexer and
//                          the various computational units comprising the ALU.
//                          Registered versions of the Logic Unit (LU) (ORA, 
//                          AND, EOR), the Arithmetic Unit (AU) (ADC, SBC, INC,
//                          DEC, CMP), the Shift Unit (SU) (ASL, LSR, ROL, ROR)
//                          and the Bit Unit (BU) (BIT, TSB, TRB) were created.
//                          The multiplexer was modified as a registered device
//                          and implements the computation unit result multi-
//                          plexer and the ALU register multiplexer. Implemen-
//                          ted a Register Write Enable and global Valid signal
//                          generator to deal with the apropriate register up-
//                          dates. Modified the stack address generation logic
//                          to accomodate the registered nature of the ALU.
//
//  1.00    11D09   MAM     Removed unused code previously commented out.
//
//  1.01    11E14   MAM     Corrected the comments regarding Q and R operand
//                          multiplexer encoding.
//
//  1.02    12A28   MAM     Added parameter to set default value of Stack Ptr
//                          after reset.
//
//  1.10    12B04   MAM     Removed pipeline registers from the ALU Valid and
//                          StkPtr signals. Also, separated the LST (Load/Store
//                          /Transfer) mux from the ALU mux for readability.
//
//  1.11    12B11   MAM     Adjusted the Shift Unit's implementation to use a
//                          common structure that clearly shows the bit being
//                          being moved into the C, and similarly, the bit vec-
//                          tor being assigned to the ALU bus. Corrected com-
//                          ment on U multiplexer of the Q bus. The X and Y 
//                          register operations listed were swapped.
//
//  1.20    12B18   MAM     Added FF to delay SetB by one cycle. This delayed
//                          signal clears the D flag and sets the I flag on the
//                          cycle after the PSW is pushed onto the stack during
//                          a BRK instruction. Also added an input, ISR, that
//                          is asserted by the interrupt processing logic after
//                          pushing the PSW so that D is cleared and I is set.
//                          In both cases, the interrupt service routines will
//                          operate in binary mode and with external maskable
//                          interrupts disabled.
//
//  1.21    12B19   MAM     Renamed module: MAM6502_ALU => M65C02_ALU.
//
//  1.30    12B20   MAM     Removed FF added by 1.20. Decided that ISR strobe,
//                          controlled by the microcode, was a better control
//                          signal for this purpose. ISR expected to be assert-
//                          ed by interrupt and break microroutines at the cor-
//                          rect time before the start of the first instruction
//                          of the interrupt/trap service routine. Since the
//                          first instruction after accepting the interrupt or
//                          executing BRK is always executed, the D and I flags
//                          do not need to be modified until the end of that
//                          instruction.
//
//                          Substantially changed the Reg_WE logic and PSW im-
//                          plementation. During RTI testing, two problems were
//                          found and corrected: (1) control of register write
//                          enables was not possible, and (2) updates to the P
//                          were occuring unexpectedly in some situations. To
//                          correct the first, the microcode was changed and a
//                          port was added that provided a 3-bit register write
//                          enable input. This 3-bit input is combined with the
//                          3-bit WSel field from the fixed microword, to gene-
//                          rate register write enables for A, X, Y, S, and P.
//                          This new structure appears to retain the desired
//                          speed, and it is easier to control the desired ac-
//                          tions using the microprogram.
//
//                          To correct the second required modifications to P
//                          register. In putting in those changes, it was appa-
//                          rent that the use of individual registers and muxes
//                          for the various input signals, was a major contri-
//                          butor to poor implementation. Thus, a single 7-bit
//                          register was implemented, with an input multiplexer
//                          the more clearly defines the input signals and data
//                          sources for each type of operation that changes the
//                          PSW at an idividual bit level or as whole.
//
//                          The changes made in these two areas allow PAR to
//                          satisfy the 100 MHz operating speed objective.
//
//  1.31    12B23   MAM     Delete commented out code. Changed WE_x equation to
//                          use Valid instead of En. Valid will be delayed by 
//                          one cycle for BDC mode ADC/SBC instructions. This
//                          is expected to correctly write the BCD result into
//                          A and the flags into P. Without switching to Valid,
//                          the BCD result would not be captured correctly into
//                          A or P. Kept En as part of the WE_S equation, the
//                          component of the equation used for inc/dec of the
//                          stack pointer during stack operations.
//
//  1.32    12B24   MAM     Modified the port list to add a ready port, Rdy.
//                          Previosly the core-level signal was applied to the
//                          ALU through the En input. Separating out Rdy allows
//                          a combinatorial logic loop to be broken. Rdy is now
//                          applied to the write enable signals. The En input
//                          drives the ALU functional units, which drive Valid
//                          in the same cycle, or in the following cycle. In
//                          the case that Valid is delayed one cycle, Rdy will
//                          be deasserted by the core-level circuit, and the
//                          cycle will be stretched. When Valid asserts, Rdy 
//                          will also assert, the registers will be written,
//                          and the cycle will continue. This cycle stretch
//                          will only occur for BCD mode ADC/SBC instructions.
//
//  1.40    12B25   MAM     Made a correction to the PSW. Further research into
//                          the operation of the PSW indicates that there are
//                          only 6 physical bits in the register itself. Bit 4
//                          in P, the programmer visible status word, is gener-
//                          ally described as the B, or Break flag. Research 
//                          indicates that this bit is not implemented as a
//                          FF. Instead, the BRK instruction forces this bit to
//                          logic 1 during the push of P to the stack. It only
//                          exists in the copy of the PSW on the stack. It is
//                          this behavior that requires a shared vector inter-
//                          rupt service routine to examine the stack version
//                          of the PSW to determine if the interrupt is a re-
//                          sult of an external IRQ or a BRK instruction. Also
//                          applied this behavior of the B bit to PHP instruc-
//                          tion. The number of FFs used to implement PSW has
//                          been decreased by 1, and the declaration of B has
//                          been removed from the source.
//
//  1.50    12K12   MAM     Modified the stack pointer logic to eliminate extra
//                          adder.
//
//  1.60    12K20   MAM     During multi-cycle microcycle, the interrupt handler
//                          was found to be modifying the PSW early. This means
//                          that the D and I flags were not properly pushed onto
//                          the stack. The modified versions of the two flags
//                          were pushed onto the stack instead of the values in
//                          the PSW at the start of the interrupt handler. Fixed
//                          by qaulifying the PSW modification with the Rdy sig-
//                          nal which signifies the end of a microcycle. Worked
//                          with single cycle microcycles, including BCD ops,
//                          because Rdy is asserted and/or the BCD op completes
//                          during the push PCH cycle. With a multi-cycle micro-
//                          cycle, the modification occurred one cycle after the
//                          push PSW microcycle, but before the data was written
//                          to the stack. Hence, qualifying it with Rdy, delays
//                          the modification until the first cycle of the next
//                          microcycle; the original intent.
//
//  2.00    12L11   MAM     Added the Rockwell instructions (RMBx, SMBx, BBRx,
//                          and BBSx) to the ALU. Modified the Bit Logical Unit
//                          to accept a new command and bit mask input. The new
//                          commands use four unused CCSel codes, and a mask
//                          provided by a new input port connected to the Decode
//                          ROM. All other changes expected to be made in the 
//                          microprogram. RMBx/SMBx can use the RMW_DP micro-
//                          routine, but BBRx/BBSx require a new microroutine.
//
//  3.00    13H04           Made the internal bus multiplexers into a one-hot
//                          decoded OR bus. Had to make some minor adjustments
//                          to the LST_En and En_RU signals to accomodate the
//                          changes in the bus multiplexer implementation.
//
// Additional Comments:
//
///////////////////////////////////////////////////////////////////////////////
 
module M65C02_ALU #(
    parameter pStkPtr_Rst = 0  // Stack Pointer Value after Reset
)(
    input   Rst,            // System Reset - synchronous reset 
    input   Clk,            // System Clock
 
    input   Rdy,            // Ready
 
    input   En,             // Enable - ALU functions
    input   [2:0] Reg_WE,   // Register Write Enable 
    input   ISR,            // Asserted on entry to Interrupt Service Routine 
 
    //  ALU Ports
 
    input   [3:0] Op,       // ALU Operation Select
    input   [1:0] QSel,     // ALU Q Bus Multiplexer Select
    input   RSel,           // ALU R Bus Multiplexer Select
    input   Sub,            // ALU Adder Operation Select
    input   CSel,           // ALU Carry In Multiplexer Select
    input   [2:0] WSel,     // ALU Register WE Select
    input   [2:0] OSel,     // ALU Output Multiplexer Select
    input   [4:0] CCSel,    // ALU Condition Code Operation Select
    input   [7:0] Msk,      // ALU Mask for Rockwell Instructions
 
    input   [7:0] M,        // ALU Memory Operand Input
    output  reg [7:0] Out,  // ALU Output(asynchronous)
    output  Valid,          // ALU Output Valid
 
    output  reg CC_Out,     // Condition Code Test Output
 
    //  Stack Pointer Output
 
    input   [1:0] StkOp,    // Stack Pointer Operation Select
 
    output  [7:0] StkPtr,   // Stack Pointer Output: {S, S+1}
 
    //  Internal Processor Registers
 
    output  reg [7:0] A,    // Accumulator
    output  reg [7:0] X,    // X Index Register
    output  reg [7:0] Y,    // Y Index Register
    output  reg [7:0] S,    // Stack Pointer
 
    output  [7:0] P         // Processor Status Word
);
 
///////////////////////////////////////////////////////////////////////////////
//
//  Local Parameter Decalarations
//
 
//  Op[3:0] Encodings
 
//  Logic Unit
localparam pALU_NOP = 0;    // NOP - No Operation: ALU<={OSel: M,A,X,Y,Z,P,S,M}
localparam pALU_AND = 1;    // AND - bitwise AND Accumulator with Memory
localparam pALU_ORA = 2;    // ORA - bitwise OR Accumulator with Memory
localparam pALU_EOR = 3;    // EOR - bitwise XOR Accumulator with Memory
//  Arithmetic Unit
localparam pALU_ADC = 4;    // ADC - Add  Memory to Accumulator + Carry
localparam pALU_SBC = 5;    // SBC - Add ~Memory to Accumulator + Carry (Sub)
localparam pALU_INC = 6;    // INC - Increment {A, X, Y, or M} (binary-only)
localparam pALU_DEC = 7;    // DEC - Decrement {A, X, Y, or M} (binary-only)
//  Shift Unit
localparam pALU_ASL = 8;    // ASL - Arithmetic Shift Left {A, or M}
localparam pALU_LSR = 9;    // LSR - Logical Shift Right {A, or M}
localparam pALU_ROL = 10;   // ROL - Rotate Left through Carry {A, or M}
localparam pALU_ROR = 11;   // ROR - Rotate Right through Carry {A, or M}
//  Bit Unit
localparam pALU_BIT = 12;   // BIT - Test Memory with Bit Mask in Accumulator
localparam pALU_TRB = 13;   // TRB - Test and Reset Memory with Bit Mask in A
localparam pALU_TSB = 14;   // TSB - Test and Set Memory with Bit Mask in A
//  Compare Unit
localparam pALU_CMP = 15;   // CMP - Compare Memory to Accumulator (binary-only)
 
//  WSel/OSel Register Select Field Codes
 
localparam pSel_A   = 1;    // Select Accumulator
localparam pSel_X   = 2;    // Select X Index
localparam pSel_Y   = 3;    // Select Y Index
localparam pSel_Z   = 4;    // Select Zero
localparam pSel_S   = 5;    // Select Stack Pointer
localparam pSel_P   = 6;    // Select PSW
localparam pSel_M   = 7;    // Select Memory Operand
 
//  Condition Code Select
 
localparam pSMB  = 4;       // Set Memory Bit
localparam pRMB  = 5;       // Reset Memory Bit
localparam pBBS  = 6;       // Branch if Memory Bit Set
localparam pBBR  = 7;       // Branch if Mmemory Bit Reset
//
localparam pCC   = 8;       // Carry Clear
localparam pCS   = 9;       // Carry Set
localparam pNE   = 10;      // Not Equal to Zero
localparam pEQ   = 11;      // Equal to Zero
localparam pVC   = 12;      // Overflow Clear
localparam pVS   = 13;      // Overflow Set
localparam pPL   = 14;      // Plus (Not Negative)
localparam pMI   = 15;      // Negative
localparam pCLC  = 16;      // Clear C
localparam pSEC  = 17;      // Set Carry
localparam pCLI  = 18;      // Clear Interrupt mask
localparam pSEI  = 19;      // Set Interrupt mask
localparam pCLD  = 20;      // Clear Decimal mode
localparam pSED  = 21;      // Set Decimal mode
localparam pCLV  = 22;      // Clear Overflow
localparam pBRK  = 23;      // Set BRK flag
localparam pZ    = 24;      // Set Z = ~|(A & M)
localparam pNZ   = 25;      // Set N and Z flags from ALU
localparam pNZC  = 26;      // Set N, Z, and C flags from ALU
localparam pNVZ  = 27;      // Set N and V flags from M[7:6], and Z = ~|(A & M)
localparam pNVZC = 28;      // Set N, V, Z, and C from ALU
//
//
localparam pPSW  = 31;      // Set P from ALU
 
///////////////////////////////////////////////////////////////////////////////
//
//  Declarations
//
 
reg     COut;                   // Carry Out -> input to C
reg     [5:0] PSW;              // Processor Status Word (Register)
wire    N, V, D, I, Z, C;       // Individual, Registered Bits in PSW
 
wire    [7:0] W, U, Q;          // Adder Input Busses
wire    [7:0] T, R;
wire    Ci;                     // Adder Carry In signal
 
//  ALU Component Output Busses
 
reg     [8:0] LU;               // Logic Unit Output
reg     LU_Valid;               // LU Output Valid
wire    [8:0] AU;               // Adder Unit Output
wire    AU_Valid;               // AU Output Valid
wire    [8:0] DU;               // Decimal (BCD) Unit Output
wire    DU_Valid;               // DU Output Valid
reg     [8:0] SU;               // Shift/Rotate Unit Output
reg     SU_Valid;               // SU Output Valid
reg     [8:0] BU;               // Bit Unit Output
reg     BU_Valid;               // BU Output Valid
 
reg     [8:0] RU;               // Rockwell Unit Output
reg     RU_Valid;               // RU Output Valid
 
wire    LST_En;                 // Load/Store/Transfer Enable
reg     [5:0] LST_Sel;          // Load/Store/Transfer Select ROM
reg     [8:0] LST;              // Load/Store/Transfer Output Multiplexer
 
reg     SelA, SelX, SelY, SelS, SelP;   // Decoded Register Write Selects
 
wire    OV;                     // Arithmetic Unit Overflow Flag
 
///////////////////////////////////////////////////////////////////////////////
//
//  Implementation
//
 
// Q Multiplexer
 
assign W = ((QSel[0]) ? M : A);     // ? INC M/DEC M : Default
assign U = ((QSel[0]) ? Y : X);     // ? INY/DEY/CPY : INX/DEX/CPX
assign Q = ((QSel[1]) ? U : W);
 
// R Multiplexer
 
assign T = ((RSel) ? 8'h01 : M);    // ? INC/DEC     : ADC/SBC/CMP (default)
assign R = ((Sub)  ? ~T    : T);    // ? SBC/DEC/CMP : ADC/INC (default)
 
// Carry In Multiplexer
 
assign Ci = ((CSel) ? Sub : C);     // ? INC/DEC/CMP : ADC/SBC (default)
 
//  M65C02 Logic, Arithmetic, Shift, and Bit Unit Implementations
 
// Logic Unit Implementation
 
assign En_LU = (En & (Op[3:2] == 2'b00) & |Op[1:0]);
 
always @(*)
begin
    if(En_LU)
        case(Op[1:0])
            2'b01   : LU <= {1'b0, A & M};           // AND
            2'b10   : LU <= {1'b0, A | M};           // ORA
            default : LU <= {1'b0, A ^ M};           // EOR
        endcase
    else
        LU <= 0;
end
 
always @(*)
begin
    LU_Valid <= En_LU;
end
 
//  Binary Adder Unit Implementation (INC/INX/INY/DEC/DEX/DEY/CMP, ADC/SBC)
 
assign En_AU = (  (En & (  (Op == pALU_ADC) | (Op == pALU_SBC)) & ~D)
                | (En & (  (Op == pALU_INC)
                         | (Op == pALU_DEC)
                         | (Op == pALU_CMP))));
 
M65C02_BIN  BIN (
                .En(En_AU),
                .A(Q),
                .B(R),
                .Ci(Ci),
                .Out(AU),
                .OV(OV_AU),
                .Valid(AU_Valid)
            );
 
//  Decimal (BCD) Adder Unit Implementation (ADC/SBC (Decimal-Only))
 
assign En_DU = (En & ((Op == pALU_ADC) | (Op == pALU_SBC)) & D);
 
M65C02_BCD  BCD (
                .Rst(Rst),
                .Clk(Clk),
                .En(En_DU),
                .Op(Sub),
                .A(Q),
                .B(R),
                .Ci(Ci),
                .Out(DU),
                .OV(OV_DU),
                .Valid(DU_Valid)
            );
 
//  Multiplex Overflow based on the Adder used
 
assign OV = ((AU_Valid) ? OV_AU : OV_DU);
 
//  Shift Unit Implementation
 
assign En_SU = (En & (Op[3:2] == 2'b10));
 
always @(*)
begin
    if(En_SU)
        case(Op[1:0])
            2'b00 : SU <= {W[7], {W[6:0], 1'b0}};   // ASL
            2'b01 : SU <= {W[0], {1'b0, W[7:1]}};   // LSR
            2'b10 : SU <= {W[7], {W[6:0], C}};      // ROL
            2'b11 : SU <= {W[0], {C, W[7:1]}};      // ROR
        endcase
    else
        SU <= 0;
end
 
always @(*)
begin
    SU_Valid <= En_SU;
end
 
// Bit Unit Implementation
 
assign En_BU = (En & ((Op[3:2] == 2'b11) & ~(Op == pALU_CMP)));
 
always @(*)
begin
    if(En_BU)
        case(Op[1:0])
            2'b01   : BU <= {1'b0,  ~A & M};    // TRB
            2'b10   : BU <= {1'b0,   A | M};    // TSB
            default : BU <= {1'b0,   A & M};    // BIT
        endcase
    else
        BU <= 0;
end
 
always @(*)
begin
    BU_Valid <= En_BU;
end
 
//  Rockwell Unit 
//  Capabilities expanded to execute the Rockwell RSBx, SMBx, BBRx, and BBSx
//  instructions. The CCSel field is used to select the operation:
//      4 - SMBx; 4 - RMBx; 6 = BBSx; 7 - BBRx;
//  if(CCSel[4:2] == 1) one of the Rockwell instructions is being executed;
//  else a normal 65C02 instruction is being executed;
//
//  For the Rockwell instructions, the mask is not provided by the accumulator.
//  Instead, the mask is provided by least significant 8 bits of the fixed
//  microword, which was added as an additional input to the module.
 
assign En_RU = (CCSel[4:2] == 4'b001);
 
always @(*)
begin
    if(En_RU)
        case(CCSel[1:0])
            2'b00 : RU <= {1'b0, Msk |  M};    // SMBx
            2'b01 : RU <= {1'b0, Msk &  M};    // RMBx
            2'b10 : RU <= {1'b0, Msk &  M};    // BBSx
            2'b11 : RU <= {1'b0, Msk & ~M};    // BBRx
        endcase
    else
        RU <= 0;
end
 
always @(*) RU_Valid <= En_RU;
 
//  Load/Store/Transfer Enable
 
assign LST_En = ((Op == pALU_NOP) & ~(CCSel[4:2] == 4'b001));
 
//  Load/Store/Transfer Multiplexer
 
always @(*)
begin
    case(OSel)
        3'b000 : LST_Sel <= 6'b000_00_1;          // LDA/PLA/LDX/PLX/LDY/PLY/PLP
        3'b001 : LST_Sel <= 6'b100_00_0;          // STA/TAX/TAY/PHA
        3'b010 : LST_Sel <= 6'b010_00_0;          // STX/TXA/TXS/PHX
        3'b011 : LST_Sel <= 6'b001_00_0;          // STY/TYA/PHY
        3'b100 : LST_Sel <= 6'b000_00_0;          // STZ
        3'b101 : LST_Sel <= 6'b000_10_0;          // TSX
        3'b110 : LST_Sel <= 6'b000_01_0;          // PHP
        3'b111 : LST_Sel <= 6'b000_00_1;          // LDA/PLA/LDX/PLX/LDY/PLY/PLP
    endcase
end
 
always @(*)
begin
    if(LST_En)
        LST <= (  ((LST_Sel[5]) ? {1'b0, A} : 0)  // STA/TAX/TAY/PHA 
                | ((LST_Sel[4]) ? {1'b0, X} : 0)  // STX/TXA/TXS/PHX 
                | ((LST_Sel[3]) ? {1'b0, Y} : 0)  // STY/TYA/PHY
                | ((LST_Sel[2]) ? {1'b0, S} : 0)  // TSX 
                | ((LST_Sel[1]) ? {1'b0, P} : 0)  // PHP
                | ((LST_Sel[0]) ? {1'b0, M} : 0));// LDA/PLA/LDX/PLX/LDY/PLY/PLP
    else
        LST <= 0;                                 // STZ
end
 
always @(*) {COut, Out} <= LU | AU | DU | SU | BU | RU | LST;
 
//  Assign ALU (Result) Valid Output (removed pipeline register 12B04, mam)
 
assign Valid = |{LU_Valid, 
                 AU_Valid,
                 DU_Valid,
                 SU_Valid,
                 BU_Valid,
                 RU_Valid,
                 LST_En   };
 
//  Condition Code Output
 
always @(*)
begin
    case(CCSel)
        pBBR    : CC_Out <= |RU;    // Added for Rockwell instructions
        pBBS    : CC_Out <= |RU;    // Added for Rockwell instructions
        //
        pCC     : CC_Out <= ~C;
        pCS     : CC_Out <=  C;
        pNE     : CC_Out <= ~Z;
        pEQ     : CC_Out <=  Z;
        pVC     : CC_Out <= ~V;
        pVS     : CC_Out <=  V;
        pPL     : CC_Out <= ~N;
        pMI     : CC_Out <=  N;
        default : CC_Out <=  1;
    endcase 
end
 
///////////////////////////////////////////////////////////////////////////////
//  Internal ALU Registers
//
 
//  Decode Register Write Enables
 
always @(*)
begin
    casex({Reg_WE, WSel})
        6'b001xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b1000_1;
        6'b100001   : {SelA, SelX, SelY, SelS, SelP} <= 5'b1000_1;
        6'b010xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0100_1;
        6'b100010   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0100_1;
        6'b011xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0010_1;
        6'b100011   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0010_1;
        6'b101xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0001_0;
        6'b100101   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0001_0;
        6'b110xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_1;
        6'b100110   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_1;
        6'b111xxx   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_1;
        6'b100111   : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_1;
        default     : {SelA, SelX, SelY, SelS, SelP} <= 5'b0000_0;
    endcase
end
 
///////////////////////////////////////////////////////////////////////////////
//
//  A - Accumulator
//
 
assign WE_A = SelA & Valid & Rdy;
 
always @(posedge Clk)
begin
    if(Rst)
        A <= #1 0;
    else if(WE_A)
        A <= #1 Out;
end
 
///////////////////////////////////////////////////////////////////////////////
//
//  X - Pre-Index Register
//
 
assign WE_X = SelX & Valid & Rdy;
 
always @(posedge Clk)
begin
    if(Rst)
        X <= #1 0;
    else if(WE_X)
        X <= #1 Out;
end
 
///////////////////////////////////////////////////////////////////////////////
//
//  Y - Post-Index Register
//
 
assign WE_Y = SelY & Valid & Rdy;
 
always @(posedge Clk)
begin
    if(Rst)
        Y <= #1 0;
    else if(WE_Y)
        Y <= #1 Out;
end
 
///////////////////////////////////////////////////////////////////////////////
//
//  P - Processor Status Word: {N, V, 1, B, D, I, Z, C}
//
 
assign WE_P = SelP & Valid & Rdy;
 
always @(posedge Clk)
begin
    if(Rst)
        PSW <= #1 6'b00_0100;       // I set by default on Rst
    else if(ISR & Rdy)
        PSW <= #1 {N, V, 1'b0, 1'b1, Z, C};
    else if(WE_P) 
        case(CCSel)
            pCLC    : PSW <= #1 {     N,   V,   D,   I,        Z,1'b0};
            pSEC    : PSW <= #1 {     N,   V,   D,   I,        Z,1'b1};
            pCLI    : PSW <= #1 {     N,   V,   D,1'b0,        Z,   C};
            pSEI    : PSW <= #1 {     N,   V,   D,1'b1,        Z,   C};
            pCLD    : PSW <= #1 {     N,   V,1'b0,   I,        Z,   C};
            pSED    : PSW <= #1 {     N,   V,1'b1,   I,        Z,   C};
            pCLV    : PSW <= #1 {     N,1'b0,   D,   I,        Z,   C};
            //
            pZ      : PSW <= #1 {     N,   V,   D,   I,~|(A & M),   C};
            pNZ     : PSW <= #1 {Out[7],   V,   D,   I,    ~|Out,   C};
            pNZC    : PSW <= #1 {Out[7],   V,   D,   I,    ~|Out,COut};
            pNVZ    : PSW <= #1 {  M[7],M[6],   D,   I,~|(A & M),   C};
            pNVZC   : PSW <= #1 {Out[7],  OV,   D,   I,    ~|Out,COut};
            pPSW    : PSW <= #1 {Out[7:6], Out[3:0]};
            default : PSW <= #1 PSW;
        endcase
end
 
//  Decode PSW bits
 
assign N = PSW[5];  // Negative, nominally Out[7], but M[7] if BIT/TRB/TSB
assign V = PSW[4];  // oVerflow, nominally OV,     but M[6] if BIT/TRB/TSB
assign D = PSW[3];  // Decimal, set/cleared by SED/CLD, cleared on ISR entry
assign I = PSW[2];  // Interrupt Mask, set/cleared by SEI/CLI, set on ISR entry
assign Z = PSW[1];  // Zero, nominally ~|Out, but ~|(A&M) if BIT/TRB/TSB
assign C = PSW[0];  // Carry, set by ADC/SBC, and ASL/ROL/LSR/ROR instructions
 
//  Assign PSW bits to P (PSW output port)
 
assign P = {N, V, 1'b1, ((CCSel == pBRK) | (OSel == pSel_P)), D, I, Z, C};
 
///////////////////////////////////////////////////////////////////////////////
//
//  Stack Pointer
//
 
assign Ld_S = Rdy & (SelS & Valid);
assign CE_S = Rdy & StkOp[1];
 
always @(posedge Clk)
begin
    if(Rst)
        S <= #1 pStkPtr_Rst;
    else if(Ld_S)
        S <= #1 X;                          // TXS
    else if(CE_S)
        S <= #1 ((StkOp[0]) ? (S + 1)       // Pop
                            : (S - 1));     // Push
end
 
//  Assign StkPtr Multiplexer for Push (0) and Pop (1) operation
//      Synchronous operation removed, 12B04, mam
 
assign StkPtr = ((&StkOp) ? (S + 1) : S);   // Stack Addrs to MAR
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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