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

Subversion Repositories cpu8080

[/] [cpu8080/] [trunk/] [project/] [cpu8080.v] - Rev 7

Go to most recent revision | Compare with Previous | Blame | View Log

`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:                                                                   //  
// Engineer:       Scott Moore                                                //
//                                                                            //
// Create Date:    11:45:32 09/04/2006                                        // 
// Design Name:                                                               // 
// Module Name:    cpu8080                                                    //
// Project Name:   cpu8080                                                    //
// Target Devices: xc3c200, xc3s1000                                          //
// Tool versions:                                                             //
// Description:                                                               //
//                                                                            //
//     Executes the 8080 instruction set. It is designed to be an internal    //
//     cell. Each of the I/Os are positive logic, and all signals are         //
//     constant with the exception of the data bus. The control signals are   //
//     fully decoded (unlike the orignal 8080), and features read and write   //
//     signals for both memory and I/O space. The I/O space is an 8 bit       //
//     address as in the original 8080.                                       //
//                                                                            //
//     Like the original 8080, the interrupt vectoring is fully external. The //
//     the external controller forces a full instruction onto the data bus.   //
//     The sequence begins with the assertion of interrupt request. The CPU   //
//     will then assert interrupt acknowledge, then it will run a special     //
//     read cycle with readint asserted for each cycle of a possibly          //
//     multibyte instruction. This matches the original 8080, which typically //
//     used single byte restart instructions to form a simple interrupt       //
//     controller, but was capable of full vectoring via insertion of a jump, //
//     call or similar instruction.                                           //
//                                                                            //
//     The memory, I/O and interrupt fetches all obey a simple clocking       //
//     sequence as follows. The CPU uses the positive clock edge to assert    //
//     and sample signals and data. The external logic theoretically uses the //
//     positive edge to check signal assertions and sample data, but it can   //
//     either use the negative edge, or actually be asynronous logic.         //
//                                                                            //
//     A standard read sequence is as follows:                                //
//                                                                            //
//     1. At the positive clock edge, readmem, readio or readint is asserted. //
//     2. At the negative clock edge (or immediately), the external memory    //
//        places data onto the data bus.                                      //
//     3. At the next positive clock edge, the data is sampled, and the read  //
//        Signal is deasserted.                                               //
//                                                                            //
//     A standard write sequence is as follows:                               //
//                                                                            //
//     1. At the positive edge, data is asserted on the data bus.             //
//     2. At the postive clock edge, writemem or writeio is asserted.         //
//     3. At the next positive clock edge, writemem or writeio is deasserted. //
//     4. At the positive edge, the data is deasserted.                       //
//                                                                            //
// Dependencies:                                                              //
//                                                                            //
// Revision:                                                                  //
// Revision 0.01 - File Created                                               //
// Additional Comments:                                                       //
//                                                                            //
// Notes:                                                                     //
//                                                                            //
// 1. Auxiliary carry is not complete.                                        //
//                                                                            //
// 2. inta should take place instead of readmem for each interrupt vector     //
//    instruction that is fetched. This behavior matches the original Intel   //
//    interrupt controller, and it should not be required to gate readmem OFF //
//    during interrupt cycles.                                                //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
 
//
// CPU states
//
 
`define cpus_idle     5'h00 // Idle
`define cpus_fetchi   5'h01 // Instruction fetch
`define cpus_fetchi2  5'h02 // Instruction fetch 2
`define cpus_halt     5'h03 // Halt (wait for interrupt)
`define cpus_alucb    5'h04 // alu cycleback
`define cpus_indcb    5'h05 // inr/dcr cycleback
`define cpus_movmtbc  5'h06 // Move memory to bc
`define cpus_movmtde  5'h07 // Move memory to de
`define cpus_movmthl  5'h08 // Move memory to hl
`define cpus_movmtsp  5'h09 // Move memory to sp
`define cpus_lhld     5'h0a // LHLD
`define cpus_jmp      5'h0b // JMP
`define cpus_write    5'h0c // write byte
`define cpus_write2   5'h0d // write byte #2
`define cpus_write3   5'h0e // write byte #3
`define cpus_write4   5'h0f // write byte #4
`define cpus_read     5'h10 // read byte
`define cpus_read2    5'h11 // read byte #2
`define cpus_pop      5'h12 // POP completion
`define cpus_in       5'h13 // IN
`define cpus_in2      5'h14 // IN #2
`define cpus_out      5'h15 // OUT
`define cpus_out2     5'h16 // OUT #2
`define cpus_out3     5'h17 // OUT #3
`define cpus_out4     5'h18 // OUT #4
`define cpus_movtr    5'h19 // move to register
`define cpus_movrtw   5'h1a // move read to write
`define cpus_movrtwa  5'h1b // move read to write address
`define cpus_movrtra  5'h1c // move read to read address
`define cpus_accimm   5'h1d // accumulator immediate operations
`define cpus_daa      5'h1e // DAA completion
 
//
// Register numbers
//
 
`define reg_b 3'b000 // B
`define reg_c 3'b001 // C
`define reg_d 3'b010 // D
`define reg_e 3'b011 // E
`define reg_h 3'b100 // H
`define reg_l 3'b101 // L
`define reg_m 3'b110 // M
`define reg_a 3'b111 // A
 
//
// ALU operations
//
 
`define aluop_add 3'b000 // add
`define aluop_adc 3'b001 // add with carry in
`define aluop_sub 3'b010 // subtract
`define aluop_sbb 3'b011 // subtract with borrow in
`define aluop_and 3'b100 // and
`define aluop_xor 3'b101 // xor
`define aluop_or  3'b110 // or
`define aluop_cmp 3'b111 // compare
 
//
// State macros
//
`define mac_writebyte  1  // write a byte
`define mac_readbtoreg 2  // read a byte, place in register
`define mac_readdtobc  4  // read double byte to BC
`define mac_readdtode  6  // read double byte to DE
`define mac_readdtohl  8 // read double byte to HL
`define mac_readdtosp  10 // read double byte to SP
`define mac_readbmtw   12 // read byte and move to write
`define mac_readbmtr   14 // read byte and move to register
`define mac_sta        16 // STA
`define mac_lda        20 // LDA
`define mac_shld       25 // SHLD
`define mac_lhld       30 // LHLD
`define mac_writedbyte 36 // write double byte
`define mac_pop        38 // POP
`define mac_xthl       40 // XTHL
`define mac_accimm     44 // accumulator immediate
`define mac_jmp        45 // JMP
`define mac_call       47 // CALL
`define mac_in         51 // IN
`define mac_out        52 // OUT
`define mac_rst        53 // RST
 
module cpu8080(addr,     // Address out
               data,     // Data bus
               readmem,  // Memory read   
               writemem, // Memory write
               readio,   // Read I/O space
               writeio,  // Write I/O space
               intr,     // Interrupt request 
               inta,     // Interrupt request 
               waitr,    // Wait request
               reset,    // Reset
               clock);   // System clock
 
   output [15:0] addr;
   inout  [7:0] data;
   output readmem;
   output writemem;
   output readio;
   output writeio;
   input  intr;
   output inta;
   input  waitr;
   input  reset;
   input  clock;
 
   // Output or input lines that need to be registered
 
   reg           readmem;
   reg           writemem;
   reg    [15:0] pc;
   reg    [15:0] addr;
   reg           readio;
   reg           writeio;
   reg           inta;
   reg    [15:0] sp;
 
   // Local registers
 
   reg    [4:0]  state;       // CPU state machine
   reg    [2:0]  regd;        // Destination register
   reg    [7:0]  datao;       // Data output register
   reg           dataeno;     // Enable output data
   reg    [15:0] waddrhold;   // address holding for write
   reg    [15:0] raddrhold;   // address holding for read
   reg    [7:0]  wdatahold;   // single byte write data holding
   reg    [7:0]  wdatahold2;  // single byte write data holding
   reg    [7:0]  rdatahold;   // single byte read data holding
   reg    [7:0]  rdatahold2;  // single byte read data holding
   reg    [1:0]  popdes;      // POP destination code
   reg    [5:0]  statesel;    // state map selector
   reg    [4:0]  nextstate;   // next state output
 
   // Register file. Note that 3'b110 (6) is not used, and is the code for a
   // memory reference.
 
   reg    [7:0]  regfil[0:7];
 
   // The flags are represented individually
 
   reg           carry; // carry bit
   reg           auxcar; // auxiliary carry bit
   reg           sign; // sign bit
   reg           zero; // zero bit
   reg           parity; // parity bit
   reg           ei; // interrupt enable
 
   // ALU communication
 
   wire   [7:0]  alures;  // result
   reg    [7:0]  aluopra; // left side operand
   reg    [7:0]  aluoprb; // right side operand
   reg           alucin;  // carry in
   wire          alucout; // carry out
   wire          alupar;  // parity out
   wire          aluaxc;  // auxiliary carry
   reg    [2:0]  alusel;  // alu operational select
 
   // Instantiate the ALU
 
   alu alu(alures, aluopra, aluoprb, alucin, alucout, aluzout, alusout, alupar,
           aluaxc, alusel);
 
   always @(posedge clock)
      if (reset) begin // syncronous reset actions
 
      state <= `cpus_fetchi; // Clear CPU state to initial fetch
      pc <= 0; // reset program counter to 1st location
      dataeno <= 0; // get off the data bus
      readmem <= 0; // all signals out false
      writemem <= 0;
      readio <= 0;
      writeio <= 0;
      inta <= 0;
      ei <= 1; // interrupts on on reset, check this
 
   end else case (state)
 
      `cpus_fetchi: begin // start of instruction fetch
 
         // interrupt is like a normal instruction cycle, except we set the 
         // acknowledge for the entire instruction fetch.
         if (intr && ei) inta <= 1; // interrupt request, set interrupt acknowledge
         else inta <= 0; // clear interrupt acknowledge
         addr <= pc; // place current program count on output
         readmem <= 1; // activate instruction memory read
         state <= `cpus_fetchi2; // next state
 
      end
 
      `cpus_fetchi2: begin // complete instruction memory read
 
         readmem <= 0; // Deactivate instruction memory read
 
         // We split off the instructions into 4 groups. Most of the 8080
         // instructions are in the MOV and ACC operations class.
 
         case (data[7:6]) // Decode top level
 
            2'b00: begin // 00: Data transfers and others
 
               case (data[5:0]) // decode these instructions
 
                  6'b000000: begin // NOP
 
                     // yes, do nothing
 
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b110111: begin // STC
 
                     carry <= 1; // set carry flag
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b111111: begin // CMC
 
                     carry <= ~carry; // complement carry flag
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b101111: begin // CMA
 
                     regfil[`reg_a] <= ~regfil[`reg_a]; // complement accumulator
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b100111: begin // DAA
 
                     // decimal adjust accumulator, or remove by carry any 
                     // results in nybbles greater than 9
 
                     if (regfil[`reg_a][3:0] > 9 || auxcar) begin
 
                        { carry, regfil[`reg_a] } <= regfil[`reg_a]+6;
                        auxcar <= (regfil[`reg_a][3:0]+6 >> 4) & 1;
 
                     end
                     state <= `cpus_daa; // finish DAA
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b000100, 6'b001100, 6'b010100, 6'b011100, 6'b100100, 
                  6'b101100, 6'b110100, 6'b111100, 6'b000101, 6'b001101, 
                  6'b010101, 6'b011101, 6'b100101, 6'b101101, 6'b110101, 
                  6'b111101: begin // INR/DCR
 
                     regd <= data[5:3]; // get source/destination reg
                     aluopra <= regfil[data[5:3]]; // load as alu a
                     aluoprb <= 1; // load 1 as alu b
                     if (data[0]) alusel <= `aluop_sub; // set subtract
                     else alusel <= `aluop_add; // set add
                     state <= `cpus_indcb; // go inr/dcr cycleback
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b000010, 6'b010010: begin // STAX
 
                     wdatahold <= regfil[`reg_a]; // place A as source
                     if (data[4]) // use DE pair
                        waddrhold <= regfil[`reg_d]<<8|regfil[`reg_d];
                     else // use BC pair
                        waddrhold <= regfil[`reg_b] << 8|regfil[`reg_c];
                     statesel <= `mac_writebyte; // write byte
                     state <= `cpus_write;
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b001010, 6'b011010: begin // LDAX
 
                     regd <= `reg_a; // set A as destination
                     if (data[4]) // use DE pair
                        raddrhold <= regfil[`reg_d]<<8|regfil[`reg_d];
                     else // use BC pair
                        raddrhold <= regfil[`reg_b]<<8|regfil[`reg_c];
                     statesel <= `mac_readbtoreg; // read byte to register
                     state <= `cpus_read;
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b000111: begin // RLC
 
                     // rotate left circular
                     { carry, regfil[`reg_a] } <= 
                        (regfil[`reg_a] << 1)+regfil[`reg_a][7];
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b010111: begin // RAL
 
                     // rotate left through carry
                     { carry, regfil[`reg_a] } <= (regfil[`reg_a] << 1)+carry;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b001111: begin // RRC
 
                     // rotate right circular
                     regfil[`reg_a] <= 
                        (regfil[`reg_a] >> 1)+(regfil[`reg_a][0] << 7);
                     carry <= regfil[`reg_a][0];
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b011111: begin // RAR
 
                     // rotate right through carry
                     regfil[`reg_a] <= (regfil[`reg_a] >> 1)+(carry << 7);
                     carry <= regfil[`reg_a][0];
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b001001: begin // DAD B
 
                     // add BC to HL
                     { carry, regfil[`reg_h], regfil[`reg_l] } <= 
                        (regfil[`reg_h] << 8)+regfil[`reg_l]+
                        (regfil[`reg_b] << 8)+regfil[`reg_c];
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b011001: begin // DAD D
 
                     // add DE to HL
                     { carry, regfil[`reg_h], regfil[`reg_l] } <= 
                        (regfil[`reg_h] << 8)+regfil[`reg_l]+
                        (regfil[`reg_d] << 8)+regfil[`reg_e];
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b101001: begin // DAD H
 
                     // add HL to HL
                     { carry, regfil[`reg_h], regfil[`reg_l] } <= 
                        (regfil[`reg_h] << 8)+regfil[`reg_l]+
                        (regfil[`reg_h] << 8)+regfil[`reg_l];
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b111001: begin // DAD SP
 
                     // add SP to HL
                     { carry, regfil[`reg_h], regfil[`reg_l] } <= 
                        (regfil[`reg_h] << 8)+regfil[`reg_l]+sp;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b000011: begin // INX B
 
                     // increment BC, no flags set
                     regfil[`reg_b] <= 
                        (((regfil[`reg_b] << 8)+regfil[`reg_c])+1)>>8;
                     regfil[`reg_c] <= 
                        ((regfil[`reg_b] << 8)+regfil[`reg_c])+1;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b010011: begin // INX D
 
                     // increment DE, no flags set
                     regfil[`reg_d] <= 
                        (((regfil[`reg_d] << 8)+regfil[`reg_e])+1)>>8;
                     regfil[`reg_e] <= 
                        ((regfil[`reg_d] << 8)+regfil[`reg_e])+1;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b100011: begin // INX H
 
                     // increment HL, no flags set
                     regfil[`reg_h] <= 
                        (((regfil[`reg_h] << 8)+regfil[`reg_l])+1)>>8;
                     regfil[`reg_l] <= 
                        ((regfil[`reg_h] << 8)+regfil[`reg_l])+1;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b110011: begin // INX SP
 
                     // increment SP, no flags set
                     sp <= sp+1;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b001011: begin // DCX B
 
                     // decrement BC, no flags set
                     regfil[`reg_b] <= 
                        (((regfil[`reg_b] << 8)+regfil[`reg_c])-1)>>8;
                     regfil[`reg_c] <= 
                        ((regfil[`reg_b] << 8)+regfil[`reg_c])-1;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b011011: begin // DCX D
 
                     // decrement DE, no flags set
                     regfil[`reg_d] <= 
                        (((regfil[`reg_d] << 8)+regfil[`reg_e])-1)>>8;
                     regfil[`reg_e] <= 
                        ((regfil[`reg_d] << 8)+regfil[`reg_e])-11;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b101011: begin // DCX H
 
                     // decrement HL, no flags set
                     regfil[`reg_h] <= 
                        (((regfil[`reg_h] << 8)+regfil[`reg_l])-1)>>8;
                     regfil[`reg_l] <= 
                        ((regfil[`reg_h] << 8)+regfil[`reg_l])-1;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b111011: begin // DCX SP
 
                     // decrement SP, no flags set
                     sp <= sp-1;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b000001: begin // LXI B
 
                     raddrhold <= pc+1; // pick up after instruction
                     statesel <= `mac_readdtobc; // read double to BC
                     state <= `cpus_read;
                     pc <= pc+3; // skip
 
                  end
 
                  6'b010001: begin // LXI D
 
                     raddrhold <= pc+1; // pick up after instruction
                     statesel <= `mac_readdtode; // read double to DE
                     state <= `cpus_read;
                     pc <= pc+3; // skip
 
                  end
 
                  6'b100001: begin // LXI H
 
                     raddrhold <= pc+1; // pick up after instruction
                     statesel <= `mac_readdtohl; // read double to HL
                     state <= `cpus_read;
                     pc <= pc+3; // skip
 
                  end
 
                  6'b110001: begin // LXI SP
 
                     raddrhold <= pc+1; // pick up after instruction
                     pc <= pc+3; // skip
                     statesel <= `mac_readdtosp; // read double to SP
                     state <= `cpus_read;
                     pc <= pc+3; // skip
 
                  end
 
                  6'b000110, 6'b001110, 6'b010110, 6'b011110, 6'b100110, 
                  6'b101110, 6'b110110, 6'b111110: begin // MVI
 
                     // move immediate to register
                     regd <= data[5:3]; // set destination register
                     raddrhold <= pc+1; // set pickup address
                     if (data[5:3] == `reg_m) begin // it's mvi m,imm
 
                        regd <= data[5:3]; // set destination register
                        // set destination address
                        waddrhold <= { regfil[`reg_h], regfil[`reg_l] };
                        statesel <= `mac_readbmtw; // read byte and move to write
 
                     end else 
                        statesel <= `mac_readbmtr; // read byte and move to register
                     state <= `cpus_read;
                     pc <= pc+2; // advance over byte
 
                  end
 
                  6'b110010: begin // STA
 
                     wdatahold <= regfil[`reg_a]; // set write data
                     raddrhold <= pc+1; // set read address
                     statesel <= `mac_sta; // perform sta
                     state <= `cpus_read;
                     pc <= pc+3; // next
 
                  end
 
                  6'b111010: begin // LDA
 
                     raddrhold <= pc+1; // set read address
                     regd <= `reg_a; // set destination
                     statesel <= `mac_lda; // perform lda
                     state <= `cpus_read;
                     pc <= pc+3; // next
 
                  end
 
                  6'b100010: begin // SHLD
 
                     wdatahold <= regfil[`reg_l]; // set write data
                     wdatahold2 <= regfil[`reg_h];
                     raddrhold <= pc+1; // set read address
                     statesel <= `mac_shld; // perform SHLD
                     state <= `cpus_read;
                     pc <= pc+3; // next
 
                  end
 
                  6'b101010: begin // LHLD
 
                     raddrhold <= pc+1; // set read address
                     statesel <= `mac_lhld; // perform LHLD
                     state <= `cpus_read;
                     pc <= pc+3; // next
 
                  end
 
                  // the illegal opcodes behave as NOPs
 
                  6'b001000, 6'b010000, 6'b011000, 6'b100000, 6'b101000, 
                  6'b110000, 6'b110000: begin 
 
                     state <= `cpus_fetchi; // fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
               endcase
 
            end
 
            2'b01: begin // 01: MOV instruction
 
               // Check its the halt instruction, which occupies the invalid
               // "MOV M,M" instruction.
               if (data == 8'b01110110) state <= `cpus_halt;
               // Otherwise, the 01 prefix is single instruction format.
               else begin
 
                  // Format 01DDDSSS
 
                  // Check memory source, use state if so
                  if (data[2:0] == `reg_m) begin
 
                     // place hl as address
                     raddrhold <= regfil[`reg_h]<<8|regfil[`reg_l];
                     regd <= data[5:3]; // set destination
                     statesel <= `mac_readbtoreg; // read byte to register
                     state <= `cpus_read;
 
                  // Check memory destination, use state if so
                  end else if (regd == `reg_m) begin
 
                     // place hl as address
                     waddrhold <= regfil[`reg_h]<<8|regfil[`reg_l];
                     wdatahold <= regfil[data[2:0]]; // place data to write
                     statesel <= `mac_writebyte; // write byte
                     state <= `cpus_write;
 
                  // otherwise simple register to register
                  end else begin
 
                     regfil[data[5:3]] <= regfil[data[2:0]];
                     state <= `cpus_fetchi; // Fetch next instruction
 
                  end
 
               end
               pc <= pc+1; // Next instruction byte
 
            end
 
            2'b10: begin // 10: Reg or mem to accumulator ops
 
               // 10 prefix is single instruction format
               aluopra <= regfil[`reg_a]; // load as alu a
               aluoprb <= regfil[data[2:0]]; // load as alu b
               alusel <= data[5:3]; // set alu operation from instruction
               alucin <= carry; // input carry
               if (data[2:0] == `reg_m) begin
 
                  // set read address
                  raddrhold <= regfil[`reg_h]<<8|regfil[`reg_l];
                  regd <= `reg_a; // set destination always a
                  statesel <= `mac_readbtoreg; // read byte to register
                  state <= `cpus_read;
 
               end else
                  state <= `cpus_alucb; // go to alu cycleback
               pc <= pc+1; // Next instruction byte
 
            end
 
            2'b11: begin // 11: jmp/call and others
 
               case (data[5:0]) // decode these instructions
 
                  6'b000101, 6'b010101, 6'b100101, 6'b110101: begin // PUSH
 
                     waddrhold <= sp-2; // write to stack
                     sp <= sp-2; // pushdown stack
                     case (data[5:4]) // register set
 
                        2'b00: { wdatahold2, wdatahold } <= 
                                  { regfil[`reg_b], regfil[`reg_c] };
                        2'b01: { wdatahold2, wdatahold } <= 
                                  { regfil[`reg_d], regfil[`reg_e] };
                        2'b10: { wdatahold2, wdatahold } <= 
                                  { regfil[`reg_h], regfil[`reg_l] };
                        2'b11: { wdatahold2, wdatahold } <= 
                                  { regfil[`reg_a], sign, zero, 1'b0, auxcar, 
                                    1'b0, parity, carry };
 
                     endcase
                     statesel <= `mac_writedbyte; // write double byte
                     state <= `cpus_write;
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b000001, 6'b010001, 6'b100001, 6'b110001: begin // POP
 
                     popdes <= data[5:4]; // set destination
                     raddrhold <= sp; // read from stack
                     sp <= sp+2; // pushup stack
                     statesel <= `mac_pop; // perform POP
                     state <= `cpus_read;
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b101011: begin // XCHG
 
                     regfil[`reg_d] <= regfil[`reg_h];
                     regfil[`reg_e] <= regfil[`reg_l];
                     regfil[`reg_h] <= regfil[`reg_d];
                     regfil[`reg_l] <= regfil[`reg_e];
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b100011: begin // XTHL
 
                     raddrhold <= sp; // address SP for read
                     waddrhold <= sp; // address SP for write
                     wdatahold <= regfil[`reg_l]; // set data is HL
                     wdatahold2 <= regfil[`reg_h];
                     statesel <= `mac_xthl; // perform XTHL
                     state <= `cpus_read;
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b111001: begin // SPHL
 
                     sp <= { regfil[`reg_h], regfil[`reg_l] };
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b000110, 6'b001110, 6'b010110, 6'b011110, 6'b100110, 
                  6'b101110, 6'b110110, 
                  6'b111110: begin // immediate arithmetic to accumulator
 
                     aluopra <= regfil[`reg_a]; // load as alu a
                     alusel <= data[5:3]; // set alu operation from instruction
                     alucin <= carry; // input carry
                     raddrhold <= pc+1; // read at PC
                     statesel <= `mac_accimm; // finish accumulator immediate
                     state <= `cpus_read;
                     pc <= pc+2; // skip immediate byte
 
                  end
 
                  6'b101001: begin // PCHL
 
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= { regfil[`reg_h], regfil[`reg_l] };
 
                  end
 
                  6'b000011: begin // JMP
 
                     raddrhold <= pc+1; // pick up jump address
                     statesel <= `mac_jmp; // finish JMP
                     state <= `cpus_read;
 
                  end
 
                  6'b000010, 6'b001010, 6'b010010, 6'b011010, 6'b100010, 
                  6'b101010, 6'b110010, 6'b111010: begin // Jcc
 
                     raddrhold <= pc+1; // pick up jump address
                     statesel <= `mac_jmp; // finish JMP
                     // choose continue or read according to condition
                     case (data[5:3]) // decode flag cases
 
                        3'b000: if (zero) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b001: if (!zero) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b010: if (carry) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b011: if (!carry) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b100: if (parity) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b101: if (!parity) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b110: if (sign) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b111: if (!sign) state <= `cpus_fetchi;
                                else state <= `cpus_read;
 
                     endcase
                     pc <= pc+3; // advance after jump for false
 
                  end
 
                  6'b001101: begin // CALL
 
                     raddrhold <= pc+1; // pick up call address
                     waddrhold <= sp-2; // place address on stack
                     { wdatahold2, wdatahold } <= pc+3; // of address after call
                     sp <= sp-2; // pushdown stack
                     statesel <= `mac_call; // finish CALL
                     state <= `cpus_read;
 
                  end
 
                  6'b000100, 6'b001100, 6'b010100, 6'b011100, 6'b100100, 
                  6'b101100, 6'b110100, 6'b111100: begin // Ccc
 
                     raddrhold <= pc+1; // pick up call address
                     waddrhold <= sp-2; // place address on stack
                     { wdatahold2, wdatahold } <= pc+3; // of address after call
                     sp <= sp-2; // pushdown stack
                     statesel <= `mac_call; // finish CALL
                     // choose continue or read according to condition
                     case (data[5:3]) // decode flag cases
 
                        3'b000: if (zero) state <= `cpus_fetchi; 
                                else state <= `cpus_read;
                        3'b001: if (!zero) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b010: if (carry) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b011: if (!carry) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b100: if (parity) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b101: if (!parity) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b110: if (sign) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b111: if (!sign) state <= `cpus_fetchi;
                                else state <= `cpus_read;
 
                     endcase
                     pc <= pc+3; // advance after jump for false
 
                  end
 
                  6'b001001: begin // RET
 
                     raddrhold <= sp; // read from stack
                     sp <= sp+2; // pushup stack
                     statesel <= `mac_jmp; // finish JMP
                     state <= `cpus_read;
 
                  end
 
                  6'b000000, 6'b001000, 6'b010000, 6'b011000, 6'b100000, 
                  6'b101000, 6'b110000, 6'b111000: begin // Rcc
 
                     raddrhold <= sp; // read from stack
                     sp <= sp+2; // pushup stack
                     statesel <= `mac_jmp; // finish JMP
                     // choose read or continue according to condition
                     case (data[5:3]) // decode flag cases
 
                        3'b000: if (zero) state <= `cpus_fetchi; 
                                else state <= `cpus_read;
                        3'b001: if (!zero) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b010: if (carry) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b011: if (!carry) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b100: if (parity) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b101: if (!parity) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b110: if (sign) state <= `cpus_fetchi;
                                else state <= `cpus_read;
                        3'b111: if (!sign) state <= `cpus_fetchi;
                                else state <= `cpus_read;
 
                     endcase
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b000111, 6'b001111, 6'b010111, 6'b011111, 6'b100111, 
                  6'b101111, 6'b110111, 6'b111111: begin // RST
 
                     pc <= data & 8'b00111000; // place restart value in PC
                     waddrhold <= sp-2; // place address on stack
                     { wdatahold2, wdatahold } <= pc+1; // of address after call
                     sp <= sp-2; // pushdown stack
                     statesel <= `mac_writedbyte; // finish RST
                     state <= `cpus_write; // write to stack
 
                  end
 
                  6'b111011: begin // EI
 
                     ei <= 1'b1;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b110011: begin // DI
 
                     ei <= 1'b0;
                     state <= `cpus_fetchi; // Fetch next instruction
                     pc <= pc+1; // Next instruction byte
 
                  end
 
                  6'b011011: begin // IN p
 
                     raddrhold <= pc+1; // pick up byte I/O address
                     pc <= pc+2; // next
                     statesel <= `mac_in; // finish IN
                     state <= `cpus_read;
                     pc <= pc+2; // Next instruction byte
 
                  end
 
                  6'b010011: begin // OUT p
 
                     raddrhold <= pc+1; // pick up byte I/O address
                     pc <= pc+2; // next
                     statesel <= `mac_out; // finish OUT
                     state <= `cpus_read;
                     pc <= pc+2; // Next instruction byte
 
                  end
 
                  // the illegal opcodes behave as NOPs
 
                  6'b001011, 6'b011001, 6'b011101, 6'b101101, 
                  6'b111101: begin
 
                     state <= `cpus_fetchi; // fetch next instruction
                     pc <= pc+2; // Next instruction byte
 
                  end
 
               endcase
 
            end
 
         endcase
 
      end
 
      // Follow states. These state handlers implement the following cycles past
      // M1, or primary fetch state.
 
      //
      // single byte write, writes wdatahold to the waddrhold address
      //
 
      `cpus_write: begin
 
         addr <= waddrhold; // place address on output
         waddrhold <= waddrhold+1; // next address
         datao <= wdatahold; // set data to output
         wdatahold <= wdatahold2; // next data
         dataeno <= 1; // enable output data
         state <= `cpus_write2; // next state
 
      end
 
      `cpus_write2: begin // continue write #2
 
         writemem <= 1; // enable write memory data
         state <= `cpus_write3; // idle one cycle for write
 
      end
 
      `cpus_write3: begin // continue write #3
 
         if (!waitr) begin // no wait selected, otherwise cycle
 
            writemem <= 0; // disable write memory data
            state <= `cpus_write4; // idle hold time
 
         end
 
      end
 
      `cpus_write4: begin // continue write #4
 
         dataeno <= 0; // disable output data
         state <= nextstate; // get next macro state
         statesel <= statesel+1; // and index next in macro 
 
      end
 
      //
      // single byte read, reads rdatahold from the raddrhold address
      //
 
      `cpus_read: begin
 
         addr <= raddrhold; // place address on output
         raddrhold <= raddrhold+1; // next address
         readmem <= 1; // activate instruction memory read
         state <= `cpus_read2; // next state
 
      end
 
      `cpus_read2: begin // continue read #2
 
         if (!waitr) begin // no wait selected, otherwise cycle
 
            rdatahold2 <= rdatahold; // shift data
            rdatahold <= data; // read new data
            readmem <= 0; // deactivate instruction memory read
            state <= nextstate; // get next macro state
            statesel <= statesel+1; // and index next in macro 
 
         end
 
      end
 
      `cpus_pop: begin // finish POP instruction
 
         case (popdes) // register set
 
            2'b00: { regfil[`reg_b], regfil[`reg_c] } <= 
                      { rdatahold, rdatahold2 };
            2'b01: { regfil[`reg_d], regfil[`reg_e] } <= 
                      { rdatahold, rdatahold2 };
            2'b10: { regfil[`reg_h], regfil[`reg_l] } <= 
                      { rdatahold, rdatahold2 };
            2'b11: begin
 
               regfil[`reg_a] <= rdatahold;
               sign <= rdatahold2 >> 7&1;
               zero <= rdatahold2 >> 6&1;
               auxcar <= rdatahold2 >> 4&1;
               parity <= rdatahold2 >> 2&1;
               carry <= rdatahold2 >> 1&1;
 
            end
 
         endcase
         state <= `cpus_fetchi; // Fetch next instruction
 
      end
 
      `cpus_jmp: begin // jump address
 
         state <= `cpus_fetchi; // and return to instruction fetch
         pc <= { rdatahold, rdatahold2 };
 
      end
 
      `cpus_in: begin // input single byte to A
 
         addr <= rdatahold; // place I/O address on address lines
         readio <= 1; // set read I/O
         state <= `cpus_in2; // continue
 
      end
 
      `cpus_in2: begin // input single byte to A #2
 
         regfil[`reg_a] <= data; // place input data
         readio <= 0; // clear read I/O
         state <= `cpus_fetchi; // Fetch next instruction
 
      end
 
      `cpus_out: begin // output single byte from A
 
         addr <= rdatahold; // place address on output
         datao <= regfil[`reg_a]; // set data to output
         dataeno <= 1; // enable output data
         state <= `cpus_out2; // next state
 
      end
 
      `cpus_out2: begin // continue out #2
 
         writeio <= 1; // enable write I/O data
         state <= `cpus_out3; // idle one cycle for write
 
      end
 
      `cpus_out3: begin // continue out #3
 
         writeio <= 0; // disable write I/O data
         state <= `cpus_out4; // idle hold time
 
      end
 
      `cpus_out4: begin // continue write #4
 
         dataeno <= 0; // disable output data
         state <= `cpus_fetchi; // Fetch next instruction
 
      end
 
      `cpus_halt: begin // Halt waiting for interrupt
 
         // nothing to do, we leave the state at halt, which will cause it to
         // be executed continually until we exit.
 
      end
 
      `cpus_movtr: begin // move to register
 
         regfil[regd] <= rdatahold; // place data
         state <= nextstate; // get next macro state
         statesel <= statesel+1; // and index next in macro 
 
      end
 
      `cpus_alucb: begin // alu cycleback
 
         regfil[`reg_a] <= alures; // place alu result back to A
         carry <= alucout; // place carry
         sign <= alusout; // place sign
         zero <= aluzout; // place zero
         parity <= alupar; // place parity
         auxcar <= aluaxc; // place auxiliary carry
         state <= `cpus_fetchi; // and return to instruction fetch
 
      end
 
      `cpus_indcb: begin // inr/dcr cycleback
 
         regfil[regd] <= alures; // place alu result back to source/dest
         sign <= alures[7]; // place sign
         zero <= aluzout; // place zero
         parity <= alupar; // place parity
         auxcar <= aluaxc; // place auxiliary carry
         state <= `cpus_fetchi; // and return to instruction fetch
 
      end
 
      `cpus_movmtbc: begin // finish LXI B
 
         regfil[`reg_b] <= rdatahold; // place upper
         regfil[`reg_c] <= rdatahold2; // place lower
         state <= `cpus_fetchi; // and return to instruction fetch
 
      end
 
      `cpus_movmtde: begin // finish LXI D
 
         regfil[`reg_d] <= rdatahold; // place upper
         regfil[`reg_e] <= rdatahold2; // place lower
         state <= `cpus_fetchi; // and return to instruction fetch
 
      end
 
      `cpus_movmthl: begin // finish LXI H
 
         regfil[`reg_h] <= rdatahold; // place upper
         regfil[`reg_l] <= rdatahold2; // place lower
         state <= `cpus_fetchi; // and return to instruction fetch
 
      end
 
      `cpus_movmtsp: begin // finish LXI SP
 
         sp <= { rdatahold, rdatahold2 }; // place
         state <= `cpus_fetchi; // and return to instruction fetch
 
      end
 
      `cpus_movrtw: begin // move read to write
 
         wdatahold <= rdatahold; // move read to write data
         state <= nextstate; // get next macro state
         statesel <= statesel+1; // and index next in macro 
 
      end
 
      `cpus_movrtwa: begin // move read data to write address
 
         waddrhold <= { rdatahold, rdatahold2 };
         state <= nextstate; // get next macro state
         statesel <= statesel+1; // and index next in macro 
 
      end
 
      `cpus_movrtra: begin // move read data to read address
 
         raddrhold <= { rdatahold, rdatahold2 };
         state <= nextstate; // get next macro state
         statesel <= statesel+1; // and index next in macro 
 
      end
 
      `cpus_lhld: begin // load HL from read data
 
         regfil[`reg_l] <= rdatahold2; // low
         regfil[`reg_h] <= rdatahold; // high
         state <= nextstate; // get next macro state
         statesel <= statesel+1; // and index next in macro 
 
      end
 
      `cpus_accimm: begin
 
         aluoprb <= rdatahold; // load as alu b
         state <= `cpus_alucb; // go to alu cycleback
 
      end
 
      `cpus_daa: begin
 
         if (regfil[`reg_a][7:4] > 9 || carry) begin
 
            { carry, regfil[`reg_a] } <= regfil[`reg_a]+8'h60;
 
         end
         state <= `cpus_fetchi; // and return to instruction fetch
 
      end
 
      default: state <= 5'bx;
 
   endcase
 
   // Enable drive for data output
   assign data = dataeno ? datao: 8'bz;
 
   //
   // State macro generator
   //
   // This ROM contains series of state execution lists that perform various
   // tasks, usually involving reads or writes.
   //
 
   always @(statesel) case (statesel)
 
      // mac_writebyte: write a byte
 
       1: nextstate = `cpus_fetchi; // fetch next instruction
 
      // mac_readbtoreg: read a byte, place in register
 
       2: nextstate = `cpus_movtr; // move to register
       3: nextstate = `cpus_fetchi; // Fetch next instruction
 
      // mac_readdtobc: read double byte to BC
 
       4: nextstate = `cpus_read; // get high byte
       5: nextstate = `cpus_movmtbc; // place in BC
 
      // mac_readdtode: read double byte to DE
 
       6: nextstate = `cpus_read; // get high byte
       7: nextstate = `cpus_movmtde; // place in DE
 
      // mac_readdtohl: read double byte to HL
 
       8: nextstate = `cpus_read; // get high byte
       9: nextstate = `cpus_movmthl; // place in HL
 
      // mac_readdtosp: read double byte to SP
 
      10: nextstate = `cpus_read; // get high byte
      11: nextstate = `cpus_movmtsp; // place in SP
 
      // mac_readbmtw: read byte and move to write
 
      12: nextstate = `cpus_movrtw; // move read to write 
      13: nextstate = `cpus_fetchi; // Fetch next instruction
 
      // mac_readbmtr: read byte and move to register
 
      14: nextstate = `cpus_movtr; // place in register
      15: nextstate = `cpus_fetchi; // Fetch next instruction
 
      // mac_sta: STA
 
      16: nextstate = `cpus_read; // read high byte
      17: nextstate = `cpus_movrtwa; // move read to write address
      18: nextstate = `cpus_write; // write to destination
      19: nextstate = `cpus_fetchi; // Fetch next instruction
 
      // mac_lda: LDA
 
      20: nextstate = `cpus_read; // read high byte
      21: nextstate = `cpus_movrtra; // move read to write address
      22: nextstate = `cpus_read; // read byte
      23: nextstate = `cpus_movtr; // move to register
      24: nextstate = `cpus_fetchi; // Fetch next instruction
 
      // mac_shld: SHLD
 
      25: nextstate = `cpus_read; // read high byte
      26: nextstate = `cpus_movrtwa; // move read to write address
      27: nextstate = `cpus_write; // write to destination low
      28: nextstate = `cpus_write; // write to destination high
      29: nextstate = `cpus_fetchi; // Fetch next instruction
 
      // mac_lhld: LHLD
 
      30: nextstate = `cpus_read; // read high byte
      31: nextstate = `cpus_movrtra; // move read to write address
      32: nextstate = `cpus_read; // read byte low
      33: nextstate = `cpus_read; // read byte high
      34: nextstate = `cpus_lhld; // move to register
      35: nextstate = `cpus_fetchi; // Fetch next instruction
 
      // mac_writedbyte: write double byte
 
      36: nextstate = `cpus_write; // double write
      37: nextstate = `cpus_fetchi; // then fetch
 
      // mac_pop: POP
 
      38: nextstate = `cpus_read; // double it
      39: nextstate = `cpus_pop; // then finish
 
      // mac_xthl: XTHL
 
      40: nextstate = `cpus_read; // double it
      41: nextstate = `cpus_write; // then write
      42: nextstate = `cpus_write; // double it
      43: nextstate = `cpus_movmthl; // place word in hl
 
      // mac_accimm: accumulator immediate
 
      44: nextstate = `cpus_accimm; // finish
 
      // mac_jmp: JMP
 
      45: nextstate = `cpus_read; // double read
      46: nextstate = `cpus_jmp; // then go pc
 
      // mac_call: CALL
 
      47: nextstate = `cpus_read; // double read
      48: nextstate = `cpus_write; // then write
      49: nextstate = `cpus_write; // double write
      50: nextstate = `cpus_jmp; // then go to that
 
      // mac_in: IN
 
      51: nextstate = `cpus_in; // go to IN after getting that
 
      // mac_out: OUT
 
      52: nextstate = `cpus_out; // go to OUT after getting that
 
      // mac_rst: RST
 
      53: nextstate = `cpus_write; // double write
      54: nextstate = `cpus_jmp; // then go to that
 
      default nextstate = 6'bx; // other states never reached
 
   endcase
 
endmodule
 
//
// Alu module
//
// Finds arithmetic operations needed. Latches on the positive edge of the
// clock. There are 8 different types of operations, which come from bits
// 3-5 of the instruction.
//
 
module alu(res, opra, oprb, cin, cout, zout, sout, parity, auxcar, sel);
 
   input  [7:0] opra;   // Input A
   input  [7:0] oprb;   // Input B
   input        cin;    // Carry in
   output       cout;   // Carry out
   output       zout;   // Zero out
   output       sout;   // Sign out
   output       parity; // parity
   output       auxcar; // auxiliary carry
   input  [2:0] sel;    // Operation select
   output [7:0] res;    // Result of alu operation
 
   reg       cout;   // Carry out
   reg       zout;   // Zero out
   reg       sout;   // sign out
   reg       parity; // parity
   reg       auxcar; // auxiliary carry
   reg [7:0] resi;   // Result of alu operation intermediate
   reg [7:0] res;    // Result of alu operation
 
   always @(opra, oprb, cin, sel, res, resi) begin
 
      case (sel)
 
         `aluop_add: begin // add
 
            { cout, resi } = opra+oprb; // find result and carry
            auxcar = (opra[3:0]+oprb[3:0]) >> 4 & 1; // find auxiliary carry
 
         end
         `aluop_adc: begin // adc
 
            { cout, resi } = opra+oprb+cin; // find result and carry
            auxcar = (opra[3:0]+oprb[3:0]+cin) >> 4 & 1; // find auxiliary carry
 
         end
         `aluop_sub, `aluop_cmp: begin // sub/cmp
 
            { cout, resi } = opra-oprb; // find result and carry
            auxcar = (opra[3:0]-oprb[3:0]) >> 4 & 1; // find auxiliary borrow
 
         end
         `aluop_sbb: begin // sbb
 
            { cout, resi } = opra-oprb-cin; // find result and carry
            auxcar = (opra[3:0]-oprb[3:0]-cin >> 4) & 1; // find auxiliary borrow
 
         end
         `aluop_and: begin // ana
 
            { cout, resi } = {1'b0, opra&oprb}; // find result and carry
            auxcar = 0; // clear auxillary carry
 
          end
         `aluop_xor: begin // xra
 
            { cout, resi } = {1'b0, opra^oprb}; // find result and carry
            auxcar = 0; // clear auxillary carry
 
         end
         `aluop_or:  begin // ora
 
            { cout, resi } = {1'b0, opra|oprb}; // find result and carry
            auxcar = 0; // clear auxillary carry
 
         end
 
      endcase
 
      if (sel != `aluop_cmp) res = resi; else res = opra;
      zout <= ~|resi; // set zero flag from result
      sout <= resi[7]; // set sign flag from result
      parity <= ~^resi; // set parity flag from result
 
   end
 
endmodule

Go to most recent revision | 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.