Advertisement
NovaYoshi

Chipmunk

Dec 17th, 2016
201
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VeriLog 13.99 KB | None | 0 0
  1. `define sFetchInstruction    4'b0000
  2. `define sFetchParameterLo    4'b0001
  3. `define sFetchParameterHi    4'b0010
  4. `define sIndexWithX          4'b0011
  5. `define sIndexWithY          4'b0100
  6. `define sReadParameterMemory 4'b0101
  7. `define sDoInstruction       4'b0110
  8. `define sCalcRelativeBranch  4'b0111
  9. `define sPushByte            4'b1000
  10. `define sPullByte            4'b1001
  11. `define sCall1               4'b1010
  12. `define sCall2               4'b1011
  13. `define sReturn1             4'b1100
  14. `define sReturn2             4'b1101
  15. `define sPointerGet1         4'b1110
  16. `define sPointerGet2         4'b1111
  17.  
  18. module chipmunk
  19.     #(parameter addrSize = 12)
  20.     (input clk,
  21.      input reset,
  22.      input [addrSize-1:0] startPC,
  23.      inout [7:0] dataBus,
  24.      output reg [addrSize-1:0] addrBus,
  25.      output weMem,
  26.      output done);
  27.  
  28.     // CPU registers
  29.     reg [7:0] aReg;              // accumulator
  30.     reg [7:0] xReg;              // X register, counter and index
  31.     reg [7:0] yReg;              // Y register, counter and index
  32.     reg [5:0] spReg;             // stack pointer
  33.     reg [addrSize-1:0] pcReg;    // program counter, current place in the program
  34.     reg [addrSize-1:0] pcRegAlt; // for saving what the PC was when calling
  35.     reg [addrSize-1:0] eaReg;    // effective address, for reading/writing bytes of memory or as a storage space for branch destionations
  36.     reg [7:0] dataReg;           // data register, for holding
  37.     reg cFlagReg, zFlagReg, nFlagReg;
  38.     reg [5:0] opcode;            // opcode storage
  39.     reg [1:0] parameter_size;    // parameter type
  40.     reg [3:0] state;             // current CPU state
  41.     reg finished;                // set to 1 when finished with the current task
  42.  
  43.     // control signals
  44.     reg [7:0] dataBusOutput;       // value we want to write to the data bus
  45.     reg [3:0] nextState;           // next state to use
  46.     wire [7:0] addSubResult;       // adds or subtracts, with or without carry
  47.     wire addSubCarryOut;
  48.     wire [7:0] shifterResult;      // shifts the accumulator or dataReg one bit left/right
  49.     wire shifterCarry;
  50.  
  51.     wire [7:0] bitOperationResult; // XOR and NOR
  52.  
  53.     wire OpLoadA        = opcode[5:1] == 5'b00000;
  54.     wire OpLoadX        = opcode[5:1] == 5'b00001;
  55.     wire OpLoadY        = opcode[5:1] == 5'b00010;
  56.     wire OpIncDecMem    = opcode[5:3] == 4'b0111 && opcode[0];
  57.     wire OpRolRorMem    = (opcode == 6'b011001 || opcode == 6'b011011);
  58.     wire OpIncDec       = opcode[5:1] == 5'b10101;
  59.     wire OpInxDex       = opcode[5:1] == 5'b10110;
  60.     wire OpInyDey       = opcode[5:1] == 5'b10111;
  61.     wire OpSta          = opcode == 6'b100001;
  62.     wire OpStx          = opcode == 6'b100011;
  63.     wire OpSty          = opcode == 6'b100101;
  64.     wire OpLdaY         = opcode == 6'b101000;
  65.     wire OpStaY         = opcode == 6'b101001;
  66.     wire OpIndexY        = opcode[5:1] == 5'b10100; // lda memory,y and sta memory,y
  67.     wire OpSetCarryFlag  = opcode[5:1] == 5'b00011;
  68.     wire OpUseAdder      = opcode[5:3] == 3'b001;
  69.     wire OpUseBitOp      = opcode[5:3] == 3'b010;
  70.     wire OpUseShifter    = opcode[5:2] == 4'b0110;
  71.  
  72.     wire OpAdderUseCarry = opcode[3:2] == 2'b11;
  73.     wire OpCpx           = opcode[5:1] == 5'b01011;
  74.     wire OpCpy           = opcode == 6'b011100;
  75.     wire OpDoCompare     = opcode[5:2] == 4'b0101 || OpCpy;
  76.     wire OpSubtractInstead = OpDoCompare ||                        // compares
  77.                              (opcode[5:1] == 5'b00101) ||          // SUB
  78.                              (opcode[5:1] == 5'b00111) ||          // SBC
  79.                              (opcode[5:3] == 3'b101 && opcode[0]); // decrements
  80.     wire aluUseX         = OpCpx || OpInxDex;
  81.     wire aluUseY         = OpCpy || OpInyDey;
  82.  
  83.     wire OpReadMemory    = opcode[0] && !opcode[5] && opcode != 6'b000111; // not SEC but everything else with this pattern
  84.  
  85.     wire OpBranch        = opcode[5:3] == 3'b111; //last 8 opcodes are branches
  86.     wire flagsMatch      = (!opcode[2] && (!opcode[1] || (opcode[0] == nFlagReg)))    // BRA/BSR, or BPL/BMI
  87.                         || (opcode[2]  && ((!opcode[1] && (opcode[0] == zFlagReg))    // BEQ/BNE
  88.                                          || (opcode[1] && (opcode[0] == cFlagReg)))); // BCS/BCC
  89.     wire BranchTaken     = OpBranch && flagsMatch;
  90.  
  91.     // -- set the finished bit to 1 when you try to RTS with a full stack
  92.     always @(posedge clk or negedge reset) begin
  93.         if (!reset)
  94.             finished = 0;
  95.         else if(opcode == 6'b100111 && spReg == 6'b111111) // RTS with a full stack = stop
  96.             finished = 1;
  97.     end
  98.  
  99.     // -- advance the current state to the next state
  100.     always @(posedge clk or negedge reset) begin
  101.         if (!reset)
  102.             state <= `sFetchInstruction;
  103.         else
  104.             state <= nextState;
  105.     end
  106.  
  107.     // -- read the opcode number and parameter size
  108.     // -- also control the effective address register
  109.     always @(posedge clk) begin
  110.         if (state == `sFetchInstruction) begin
  111.             opcode <= dataBus[7:2];
  112.             parameter_size <= dataBus[1:0];
  113.             eaReg <= 0;   // address register is zero
  114.             if(dataBus[7:1] == 5'b10101 || dataBus[7:1] == 5'b10110 || dataBus[7:1] == 5'b10111 || (dataBus[7:5] == 4'b0111 && dataBus[0]))
  115.                 // (in order: INC/DEC A, INX/DEX, INY/DEY, INC/DEC memory)
  116.                 dataReg <= 1; // data register is 1, for incrementing/decrementing
  117.             else
  118.                 dataReg <= 0; // data register is zero
  119.         end else if(state == `sFetchParameterLo) begin // load data register and low byte of address simultaneously
  120.             dataReg <= dataBus;
  121.             eaReg[7:0] <= dataBus;
  122.         end else if(state == `sFetchParameterHi) // load high byte of address
  123.             eaReg[addrSize-1:8] <= dataBus;        
  124.         else if (state == `sIndexWithX) // index with X
  125.             eaReg <= eaReg + xReg;
  126.         else if (state == `sIndexWithY) // index with Y
  127.             eaReg <= eaReg + yReg;
  128.         else if (state == `sCalcRelativeBranch) // relative branch, sign extend branch distance and add it to PC
  129.             eaReg <= {{8{dataReg[7]}}, dataReg[7:0]} + pcReg;
  130.         else if (state == `sPointerGet1) // get low byte of pointer
  131.             eaReg[7:0] <= dataBus;
  132.         else if (state == `sPointerGet2) // get high byte of pointer
  133.             eaReg[addrSize-1:8] <= dataBus;
  134.     end
  135.  
  136.     // -- stack pointer
  137.     // can increment or decrement
  138.     always @(posedge clk or negedge reset) begin
  139.         if (!reset)
  140.             spReg <= 6'b111111;
  141.         else if (state == `sReturn1 ||
  142.                 (state == `sFetchInstruction &&
  143.                     ((dataBus[7:4] == 4'b1100 && dataBus[0]) // pla, plx, ply, plp
  144.                     || (dataBus[7:2] == 6'b100111)) // rts
  145.                 ))
  146.             spReg <= spReg + 1'b1;
  147.         else if (state == `sPushByte ||
  148.                  state == `sCall1 ||
  149.                  state == `sCall2)
  150.             spReg <= spReg - 1'b1;
  151.     end
  152.  
  153.     // -- Adder/subtractor
  154.     wire [7:0] aluLeft = aluUseX ? xReg : (aluUseY ? yReg : aReg);
  155.     assign { addSubCarryOut, addSubResult } =
  156.         OpAdderUseCarry ? (OpSubtractInstead ? // carry
  157.             aluLeft + {1'b0, ~dataReg[7:0]} + cFlagReg
  158.             : aluLeft + dataReg + cFlagReg)
  159.         : (OpSubtractInstead ? // no carry
  160.             aluLeft + {1'b0, ~dataReg[7:0]} + 1'b1 // add two's complement
  161.             : aluLeft + dataReg);
  162.  
  163.     // -- Bit operations
  164.     assign bitOperationResult = opcode[1] ? (aReg ^ dataReg) : ~(aReg | dataReg);
  165.  
  166.     wire [7:0] shifterLeft = opcode[0] ? dataReg : aReg;
  167.     assign shifterResult = opcode[2] ? // shift left or shift right?
  168.             (shifterLeft >> 1) | ((opcode[0] && cFlagReg) ? 8'b10000000 : 8'b00000000) // memory uses rotates
  169.             :(shifterLeft << 1) | ((opcode[0] && cFlagReg) ? 8'b00000001 : 8'b00000000);
  170.     assign shifterCarry = opcode[2] ? shifterLeft[0] : shifterLeft[7];
  171.  
  172.     // -- A (accumulator) register
  173.     always @(posedge clk) begin
  174.         if (state == `sDoInstruction) begin
  175.             if (OpLoadA || OpLdaY) // LDA
  176.                 aReg <= dataReg;
  177.             else if (OpUseAdder || OpIncDec) // ADD, SUB, ADC, SBC, INC, DEC
  178.                 aReg <= addSubResult;
  179.             else if (OpUseBitOp) // NOR, XOR
  180.                 aReg <= bitOperationResult;
  181.             else if (OpUseShifter && !opcode[0]) // ASL, LSR
  182.                 aReg <= shifterResult;
  183.             else if (opcode == 6'b100100 || opcode == 6'b100110) // TXA, SWAP
  184.                 aReg <= xReg;
  185.         end else if(state == `sPullByte && opcode[2:1] == 2'b01) // PLA
  186.             aReg <= dataBus;
  187.     end
  188.  
  189.     // -- X register
  190.     always @(posedge clk) begin
  191.         if (state == `sDoInstruction) begin
  192.             if (OpLoadX) // LDX
  193.                 xReg <= dataReg;
  194.             else if(OpInxDex) // INX, DEX
  195.                 xReg <= addSubResult;
  196.             else if (opcode == 6'b100010 || opcode == 6'b100110) // TAX, SWAP
  197.                 xReg <= aReg;
  198.         end else if(state == `sPullByte && opcode[2:1] == 2'b10) // PLX
  199.             xReg <= dataBus;
  200.     end
  201.  
  202.     // -- Y register
  203.     always @(posedge clk) begin
  204.         if (state == `sDoInstruction) begin
  205.             if (OpLoadY) // LDY
  206.                 yReg <= dataReg;
  207.             else if(OpInyDey) // INY, DEY
  208.                 yReg <= addSubResult;
  209.         end else if(state == `sPullByte && opcode[2:1] == 2'b11) // PLY
  210.             yReg <= dataBus;
  211.     end
  212.  
  213.     // -- flags registers
  214.     always @(posedge clk) begin
  215.         if (state == `sDoInstruction) begin
  216.             if (opcode[5:1] == 5'b00011) // CLC, SEC
  217.                 cFlagReg <= opcode[0];
  218.             else if (OpUseAdder || OpIncDec || OpInxDex || OpInyDey || OpIncDecMem) begin // add/subtract and increments/decrements all use the adder
  219.                 nFlagReg <= addSubResult[7];
  220.                 zFlagReg <= (addSubResult == 8'b00000000) ? 1 : 0;
  221.                 if (OpUseAdder) // increment/decrement doesn't affect carry
  222.                     cFlagReg <= addSubCarryOut;
  223.             end else if(OpUseBitOp) begin
  224.                 nFlagReg <= bitOperationResult[7];
  225.                 zFlagReg <= (bitOperationResult == 8'b00000000) ? 1 : 0;
  226.             end else if(OpUseShifter) begin
  227.                 nFlagReg <= shifterResult[7];
  228.                 zFlagReg <= (shifterResult == 8'b00000000) ? 1 : 0;
  229.                 cFlagReg <= shifterCarry;
  230.             end else if(OpLoadA || OpLoadX || OpLoadY) begin
  231.                 nFlagReg <= dataReg[7];
  232.                 zFlagReg <= (dataReg == 8'b00000000) ? 1 : 0;
  233.             end
  234.         end else if(state == `sPullByte && opcode[2:1] == 2'b00)
  235.             {nFlagReg, zFlagReg, cFlagReg} <= dataBus[2:0];
  236.     end
  237.  
  238.     // -- program counter
  239.     // can increment or load
  240.     always @(posedge clk or negedge reset) begin
  241.         if (!reset)
  242.             pcReg <= startPC;
  243.         else if(state == `sFetchInstruction || state == `sFetchParameterLo || `sFetchParameterHi)
  244.             pcReg <= pcReg + 1'b1;
  245.         else if(state == `sDoInstruction && BranchTaken) begin
  246.             pcRegAlt <= pcReg;                 // save a copy of the program counter so it can get pushed afterwards
  247.             pcReg <= eaReg;
  248.         end else if(state == `sReturn1) begin
  249.             pcRegAlt[7:0] <= dataBus;          // load half of the new program counter
  250.         end else if(state == `sReturn2) begin
  251.             pcReg <= {pcRegAlt[7:0], dataBus}; // load the other half of the program counter and combine it with the saved one
  252.         end
  253.     end
  254.  
  255.     // -- address output
  256.     always @* begin
  257.         case (state)
  258.             `sReadParameterMemory: // read a byte from memory
  259.                 addrBus <= eaReg;
  260.             `sPushByte, `sPullByte, `sCall1, `sCall2, `sReturn1, `sReturn2:
  261.                 addrBus <= { {(addrSize-9){1'b0}}, 1'b0, 1'b0, 1'b0, spReg }; // stack goes in $01xx
  262.             `sFetchInstruction, `sFetchParameterLo, `sFetchParameterHi: // read parameter parts
  263.                 addrBus <= pcReg;
  264.             `sPointerGet1:
  265.                 addrBus <= {{{8}{1'b0}}, dataReg};
  266.             `sPointerGet2:
  267.                 addrBus <= {{{8}{1'b0}}, dataReg+1};
  268.             default:
  269.                 addrBus <= {{addrSize}{1'bx}};
  270.         endcase
  271.     end
  272.        
  273.     // -- data output
  274.     always @* begin
  275.         if (state == `sDoInstruction && (OpSta || OpStaY))
  276.             dataBusOutput <= aReg;
  277.         else if (state == `sDoInstruction && OpStx)
  278.             dataBusOutput <= xReg;
  279.         else if (state == `sDoInstruction && OpSty)
  280.             dataBusOutput <= yReg;
  281.         else if (state == `sDoInstruction && OpRolRorMem) // ROL/ROR
  282.             dataBusOutput <= shifterResult;
  283.         else if (state == `sDoInstruction && OpIncDecMem) // INC/DEC
  284.             dataBusOutput <= addSubResult;
  285.         else if (state == `sPushByte) // figure out what byte to push
  286.             dataBusOutput <= (opcode[2:1] == 2'b00) ? {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, nFlagReg, zFlagReg, cFlagReg} :
  287.                              (opcode[2:1] == 2'b01) ? aReg :
  288.                              (opcode[2:1] == 2'b10) ? xReg :
  289.                              yReg;
  290.         else if (state == `sCall1)
  291.             dataBusOutput <= pcRegAlt[7:0];
  292.         else if (state == `sCall2)
  293.             dataBusOutput <= { {(16-addrSize){1'b0}}, pcRegAlt[addrSize-1:8] };
  294.         else
  295.             dataBusOutput <= 8'bxxxxxxxx;
  296.     end
  297.  
  298.     wire writeCycle =  ((state == `sDoInstruction && (OpSta || OpStx || OpSty || OpStaY || OpIncDecMem || OpRolRorMem)) || state == `sPushByte || state == `sCall1 || state == `sCall2);
  299.  
  300.     assign weMem = !(writeCycle & !clk); // only assert we during 2nd half of the clock cycle
  301.     assign dataBus = !weMem ? dataBusOutput : 8'bzzzzzzzz;
  302.     assign done = finished;
  303.  
  304.     // -- control logic: state machine
  305.     always @* begin    
  306.         case (state)
  307.             `sFetchInstruction:
  308.                 nextState = (dataBus[7:5] == 3'b110 && dataBus[0]) ? `sPushByte :
  309.                     (dataBus[7:5] == 3'b110 && !dataBus[0]) ? `sPullByte :
  310.                     (parameter_size[0] || parameter_size[1]) ? `sFetchParameterLo :
  311.                     (OpReadMemory ? `sReadParameterMemory : `sDoInstruction);
  312.             `sFetchParameterLo:
  313.                 nextState = parameter_size[1] ? `sFetchParameterHi :  // keep getting parameter bytes if there's more
  314.                            (OpReadMemory ? `sReadParameterMemory :    // read memory
  315.                            (OpBranch ? `sCalcRelativeBranch :         // did we stop here on a branch? it's relative then
  316.                            (OpIndexY ? `sPointerGet1 :                // start to get a pointer if a Y index opcode
  317.                            `sDoInstruction)));                        // or I guess we're done? go do the opcode
  318.             `sFetchParameterHi:
  319.                 nextState = parameter_size[0] ? `sIndexWithX :        // index with X
  320.                 (OpReadMemory ? `sReadParameterMemory :               // read byte first
  321.                 (OpIndexY ? `sIndexWithY :                            // index with Y
  322.                 `sDoInstruction));
  323.             `sIndexWithX:
  324.                 nextState = OpReadMemory ? `sReadParameterMemory : `sDoInstruction;
  325.             `sReadParameterMemory, `sCalcRelativeBranch:              // done doing any additional preparation, start the actual instruction effect
  326.                 nextState = `sDoInstruction;
  327.             `sDoInstruction, `sPushByte, `sPullByte, `sCall2, `sReturn2:
  328.                 nextState = (BranchTaken && opcode[2:0] == 3'b001) ? `sCall1 : `sFetchInstruction; // start a pushing the old program counter if needed
  329.             `sIndexWithY:
  330.                 nextState = OpLdaY ? `sReadParameterMemory : `sDoInstruction;
  331.             `sReturn1:
  332.                 nextState = `sReturn2;
  333.             `sCall1:
  334.                 nextState = `sCall2;
  335.             `sPointerGet1: // read the low byte of the pointer
  336.                 nextState = `sPointerGet2;
  337.             `sPointerGet2: // read the high byte of the pointer
  338.                 nextState = `sIndexWithY;
  339.         endcase
  340.     end
  341. endmodule
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement