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

Subversion Repositories wb_z80

[/] [wb_z80/] [tags/] [arelease/] [rtl/] [memstate.v] - Rev 39

Compare with Previous | Blame | View Log

///////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                               //
//  file name:   memstate.v                                                                       //
//  description: memory opertions for  z80                                                       //
//  project:     wb_z80                                                                          //
//                                                                                               //
//  Author: B.J. Porcella                                                                        //
//  e-mail: bporcella@sbcglobal.net                                                              //
//                                                                                               //
//                                                                                               //
//                                                                                               //
///////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                               //
// Copyright (C) 2000-2002 B.J. Porcella                                                         //
//                         Real Time Solutions                                                   //
//                                                                                               //
//                                                                                               //
// This source file may be used and distributed without                                          //
// restriction provided that this copyright statement is not                                     //
// removed from the file and that any derivative work contains                                   //
// the original copyright notice and the associated disclaimer.                                  //
//                                                                                               //
//     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY                                       //
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED                                     //
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS                                     //
// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR                                        //
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,                                           //
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES                                      //
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE                                     //
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR                                          //
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF                                    //
// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT                                    //
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT                                    //
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE                                           //
// POSSIBILITY OF SUCH DAMAGE.                                                                   //
//                                                                                               //
//-------1---------2---------3--------Comments on file  -------------7---------8---------9--------0
// The memory state controller controls the wb bus, and provides address sequencing.
// Insructions are fetched in order (using PC) until the istate machine indicates that 
// a complete instruction is in the first pipline stage (ir1). In general, operands are being
// fetched (stored) to satisfy ir1 while concurrently instructions are being executed from ir2.
// this situation can result in a number of potential hazards.   As an example, if the ir2
// instruction changes the flag register and the ir1 instruction is a conditional jump, 
// a hazard is generated by the hazard logic, and execution of the ir1 operation is delayed 
// until the completion of the flag update.
//
// Reset starts execution at 0.  
// The PC and SP are described in this file.   modifications to other index registers - 
// HL IX and IY are computed here -- 
// For the block moves address updates are computed here   -- and commanded here.
// Strobes for the second address update are generally co-incident with count updates, but
// we provide seperate strobe update lines for clarity.
//
//  BASIC ARCHITECTURE OF THIS FILE   pc  and sp not shown, but are inputs to src mux.
//                    _____           and may be updated from adder output.
//                   |     |
//                   |     |          pc-1 register is required to implement relative jumps.
//                   |     |                     
//      _____        |lit  |      |\             
//     |     |       |     |      |  \           
//     |     |       |src2 |      |    \          _____          _____ 
//     |     |       |     |----->|     |        |     |        |     |
//     |src  |       |_____|      |adder|------->|     |        |     |
//     |mux  |                    |     |        |     |        |     |
//     |     |------------------->|    /         |2/1  |------->|wb   |
//     |     |              |     |  /           |mux  |        |adr  |
//     |_____|              |     |/             |     |        |     |
//                           ------------------->|     |        |     |
//                                               |_____|        |_____|
//
//
//
//
//  Operand Stores:
//  At first cut, I thought I'ld execute operand stores immediately from the memory sequencer
//  (essentially before ir2 got the store data).  While this might be modestly faster in 
//  systems that take multiple clocks to complete a memory store, On consideration, I decided 
//  to forgo the extra speed for conceptual simplicity....   execute operand stores on op_ph1,
//  and let the inst_exec engine suply the operand.
//
//  On second thought, above is not only wastful of time, but also inconsistent with the overall
//  schems of things - and so somewhat more complex. If we simply execute the OS from ir1, 
//  There is less state to contdend with, as well as extra speed.
//
//  Block Moves fundamentally execute from ir2.  We initiate the first operand fetch from ir1.
//
//  3/18/2004 Second time through.   In impleenting the execution logic it became clear that
//  there were "minor" problems with the handling of the DD and FD prefix insts (especially
//  DDCD and FDCB  ---  collectively called PFxCB below.  On review, I had to question the
//  value of "breaking up" the ir0 execution engine between the istate sequencer and the 
//  memstate sequencer.   While I dislike state sequencers of much more than 16 states  --  
//  
//   
//
//  Hazards:
//  There are 2 kinds of hazards:  mem_hazard => we are storing into the next instruction location
//                                 reg_hazard => we are modifying a register (ir2) that we are using
//                                                here (ir1)
//  In the former case, we throw out the instruction that arrives on the next tick, and restart the
//  instruction pipeline,   In the latter case, we simply wait a tick for the ir2 operaton to 
//  complete before starting the ir1 operation  
//-------1---------2---------3--------CVS Log -----------------------7---------8---------9--------0
//
//  $Id: memstate.v,v 1.1.1.1 2004-04-13 23:50:05 bporcella Exp $
//
//  $Date: 2004-04-13 23:50:05 $
//  $Revision: 1.1.1.1 $
//  $Author: bporcella $
//  $Locker:  $
//  $State: Exp $
//
// Change History:
//      $Log: not supported by cvs2svn $
//
//
//-------1---------2---------3--------Module Name and Port List------7---------8---------9--------0
module memstate(wb_adr, wb_we, wb_cyc, wb_stb, wb_lock, wb_tga_io,  add_out,
                use_sp,use_a,use_b,use_c,use_d,use_e,use_h,use_l,use_flags, // these for hazard detection                                                         
                ir1, ir1cb, ir1ed, ir1dd, ir1fd, ir1_exec,
                nn, hl, ix, iy, de, bc, 
                stb_hl, stb_ix, stb_iy, stb_de, upd_blk_cnt,
                beq0, ceq0,
                hazard, wb_ack, clk, rst
 
 
 
 
);
 
//-------1---------2---------3--------Output Ports---------6---------7---------8---------9--------0
 
output [15:0]  wb_adr; 
output         wb_we; 
output         wb_cyc; 
output         wb_stb; 
output         wb_lock;     // bit set and clear insts should be atomic - could matter sometime
output         wb_tga_io;  
output [15:0]  add_out;     // output of adder  (may not wb_adr)
 
output          use_sp;     // these for hazard detection
output          use_a;
output          use_b;
output          use_c;
output          use_d
output          use_e;
output          use_h;
output          use_l;
output          use_flags;
 
 
 
 
 
 
 
 
//-------1---------2---------3--------Input Ports----------6---------7---------8---------9--------0
 
input [9:0]     ir1; 
input           ir1cb; 
input           ir1ed; 
input           ir1_exec;    // ir1 data is ready to execute.
input           mem_hazard;      // throw out next inst and restart inst pipeline
input           reg_hazard;      // wait a tick to execute. (this signal is slow) 
input           beq0, ceq0;
 
 
 
 
//-------1---------2---------3--------Parameters-----------6---------7---------8---------9--------0
`include "opcodes.v"            //  states of the main memory sequencer
parameter   MEM_IDLE  = 4'h0,
            MEM_HALT  = 4'h1,   //  go here after a HALT instruction
            MEM_IF1   = 4'h2,   //  start the instruction fetch pipt
            MEM_IF2   = 4'h3,   //  continue the if pipe
            MEM_EXEC  = 4'h4,   //  main ir1 execution state - decode and do what is needed
            MEM_OP1   = 4'h5,   //  go here if instruction needs more than 1 operand operation
            MEM_OP2   = 4'h6,   //  go here if OP1 not sufficent (rare)
            MEM_OP3   = 4'h7,   //  go here if OP2 not sufficient (rare but used by blk rpt
            MEM_RPT   = 4'h8,   //  go here for block repeat tests  (must allow interrupts)
            MEM_INT1  = 4'ha,   //  int sequence is messy  --  seperate states for that
            MEM_INT2  = 4'hb,
            MEM_INT3  = 4'hc;
            MEM_INT4  = 4'hd,
            MEM_INT5  = 4'he;
 
parameter   TAG_IO    = 2'b01;   // need to review general wb usage to undrstand how best to 
            TAG_INT   = 2'b10;   // document this. 
 
//-------1---------2---------3--------Wires----------------6---------7---------8---------9--------0
 
wire        of8;
wire        of16;
wire        os8
wire        os16;
wire        rmw8;
wire        jmp;
wire        call;
wire        ret;
wire        ioi;  // io input
wire        ioo;  // io output
wire        blk_mv;
wire        blk_cmp;
wire        blk_in;
wire        blk_out;
wire        use_sp;   
wire        use_pc; 
wire        use_hl; 
wire        use_de; 
wire        use_bc; 
wire        use_flags;
wire        cb_mem;
wire        br_test8t;  // branch test true  (8 test field)
wire        br_test4t;  // branch test true  (4 test field)
wire        src_mux;
wire        src2;   
wire        alu;    
wire        mux21;
wire        mem_idle ;
wire        mem_halt ;
wire        mem_if1  ;
wire        mem_if2  ;
wire        mem_exec ;
wire        mem_op1  ;
wire        mem_op2  ;
wire        mem_op3  ;
wire        mem_int1 ;
wire        mem_int2 ;
wire        mem_int3 ;
wire        mem_int4 ;
wire        mem_int5 ;
wire        exec_if;    // perform an instruction fetch on mem_exec  (instruction is reg<-reg)                     
wire        ofos; 
wire        any_os;   // most terms above only valid on mem_exec  this includes all stores
wire        wb_rdy;        
 
 
//-------1---------2---------3--------Registers------------6---------7---------8---------9--------0
 
reg [15:0]   pc, pc_min1;
reg [15:0]   sp;
reg [15:0]   wb_adr;
reg          wb_we; 
reg          wb_cyc; 
reg          wb_stb; 
reg          wb_lock; 
reg          wb_tga_io
 
 
 
 
 
// don't forget that as 1r1 is executed it is transferred to ir2.  Anything I need to know
// about subsequent operations must be stored.
reg  [        mem_state
reg          of16_reg,  os16_reg, rmw8_reg, call_reg, ret_reg, ioi;
reg          push_reg;
reg          pop_reg; 
//-------1---------2---------3--------Assignments----------6---------7---------8---------9--------0
//
// ir is 10 bits most significant codes ir[9:8] = { EDgrp, CBgrp }  DDgrp and FDgrp are modifiers
 
assign   cb_mem = CB_MEM = ir1[2:0];                 // CB_MEM  = 3'h110,    
 
assign   of8 = LDsA_6BC7  == ir1 |      // LD A,(BC)    ; 0A
               LDsA_6DE7  == ir1 |      // LD A,(DE)    ; 1A
               LDsB_6HL7  == ir1 |      // LD B,(HL)    ; 46
               LDsD_6HL7  == ir1 |      // LD D,(HL)    ; 56
               LDsH_6HL7  == ir1 |      // LD H,(HL)    ; 66
               ADDsA_6HL7 == ir1 |      // ADD A,(HL)   ; 86
               SUBs6HL7   == ir1 |      // SUB (HL)     ; 96
               ANDs6HL7   == ir1 |      // AND (HL)     ; A6
               ORs6HL7    == ir1 |      // OR (HL)      ; B6
               LDsC_6HL7  == ir1 |      // LD C,(HL)    ; 4E
               LDsE_6HL7  == ir1 |      // LD E,(HL)    ; 5E
               LDsL_6HL7  == ir1 |      // LD L,(HL)    ; 6E
               LDsA_6HL7  == ir1 |      // LD A,(HL)    ; 7E
               ADCsA_6HL7 == ir1 |      // ADC A,(HL)   ; 8E
               SBCs6HL7   == ir1 |      // SBC (HL)     ; 9E
               XORs6HL7   == ir1 |      // XOR (HL)     ; AE
               CPs6HL7    == ir1 |      // CP (HL)      ; BE
               LDsA_6NN7  == ir1 |      // LD A,(NN)    ; 3A XX XX
               cb_mem &  CB_BIT  == ir2[9:6];    // (HL) these must be compaired with ir[7:6]
 
assign   of16;  LDsHL_6NN7   == ir1 |  //      LD HL,(NN)   ; 2A XX XX
                POPsAF       == ir1 |  //      POP AF       ; F1   AF<- (SP++ ++)  
                POPsBC       == ir1 |  //      POP BC       ; C1   BC<- (SP++ ++)  
                POPsDE       == ir1 |  //      POP DE       ; D1   DE<- (SP++ ++)  
                POPsHL       == ir1 |  //      POP HL       ; E1   HL<- (SP++ ++)  
                ED_LDsREG_6NN7 == {ir[7:6],ir[3:0]}   //   REG = BC,DE,HL,SP
 
assign   os8  = LDs6HL7_N    == ir1 |  //      LD (HL),N    ; 36 XX
                LDs6BC7_A    == ir1 |  //      LD (BC),A    ; 02 
                LDs6DE7_A    == ir1 |  //      LD (DE),A    ; 12
                LDs6HL7_A    == ir1 |  //      LD (HL),A    ; 77
                LDs6HL7_B    == ir1 |  //      LD (HL),B    ; 70
                LDs6HL7_C    == ir1 |  //      LD (HL),C    ; 71
                LDs6HL7_D    == ir1 |  //      LD (HL),D    ; 72
                LDs6HL7_E    == ir1 |  //      LD (HL),E    ; 73
                LDs6HL7_H    == ir1 |  //      LD (HL),H    ; 74
                LDs6HL7_L    == ir1 |  //      LD (HL),L    ; 75
                LDs6NN7_A    == ir1 ;  //      LD (NN),A    ; 32 XX XX
 
assign  os16 = PUSHsAF      == ir1 |      //      PUSH AF      ; F5   (-- --SP) <- AF
               PUSHsBC      == ir1 |      //      PUSH BC      ; C5   (-- --SP) <- BC
               PUSHsDE      == ir1 |      //      PUSH DE      ; D5   (-- --SP) <- DE
               PUSHsHL      == ir1 |      //      PUSH HL      ; E5   (-- --SP) <- HL
               LDs6NN7_HL   == ir1 |            //      LD (NN),HL   ; 22 XX XX
               ED_LDs6NN7_REG = {ir[7:6],ir[3:0]}; //REG = BC,DE,HL,SP                    
 
 
// these are executed  ; exec(of) ; op1(nop); op2(os) ; if2
assign  rmw8 = INCs6HL7        == ir1     | //  INC (HL)     ; 34
               DECs6HL7        == ir1     | //  DEC (HL)     ; 35 
               cb_mem & CB_RLC == ir1[9:3] |  //(HL)
               cb_mem & CB_RRC == ir1[9:3] |  //(HL)
               cb_mem & CB_RL  == ir1[9:3] |  //(HL)
               cb_mem & CB_RR  == ir1[9:3] |  //(HL)
               cb_mem & CB_SLA == ir1[9:3] |  //(HL)
               cb_mem & CB_SRA == ir1[9:3] |  //(HL)
               cb_mem & CB_SRL == ir1[9:3] |  //(HL)
               cb_mem & CB_RES == ir1[9:6] |   //(HL)
               cb_mem & CB_SET == ir1[9:6] ;   //(HL)
 
// this is executd   exec(of) ; op1(os) ; op2(of) ; op3(os) ; if2              
assign xchng16 =  EXs6SP7_HL  == ir1; //      EX (SP),HL   ; E3               
 
// cond jumps are executed exec cond_t?  pc,wb_adr<-adr if goto if2 : if goto exec
wire  c_jmp8 = JPsC  == ir1  |     // JP C,$+3     ; DA XX  XX
               JPsM  == ir1  |     // JP M,$+3     ; FA XX  XX
               JPsNC == ir1  |     // JP NC,$+3    ; D2 XX  XX
               JPsNZ == ir1  |     // JP NZ,$+3    ; C2 XX  XX
               JPsPE == ir1  |     // JP PE,$+3    ; EA XX  XX
               JPsPO == ir1  |     // JP PO,$+3    ; E2 XX  XX
               JPsP  == ir1  |     // JP P,$+3     ; F2 XX  XX
               JPsZ  == ir1  ;     // JP Z,$+3     ; CA XX  XX
 
wire c_jmp4 = JRsC_$t2     == ir1  |
              JRsNC_$t2    == ir1  |
              JRsNZ_$t2    == ir1  |
              JRsZ_$t2     == ir1  ;
 
assign jmp =  JRs$t2       == ir1  |     // JR $+2       ; 18  XX
              DJNZs$t2     == ir1  |     // DJNZ $+2     ; 10 XX  XX
              JPs          == ir1  |     // JP $+3       ; C3 XX  XX
              JPsHL == ir1         |     // JP HL        ; E9 // documented as indirect is not
              c_jmp4 & br_test4t   |   // JR C,$+2     ; 38
              c_jmp8 & br_test8t   |     // JP C,$+3     ; DA XX  XX
              RSTs0        == ir1  |     // RST 0        ; C7
              RSTs8H       == ir1  |     // RST 8H       ; CF 
              RSTs10H      == ir1  |     // RST 10H      ; D7
              RSTs18H      == ir1  |     // RST 18H      ; DF
              RSTs20H      == ir1  |     // RST 20H      ; E7
              RSTs28H      == ir1  |     // RST 28H      ; EF        
              RSTs30H      == ir1  |     // RST 30H      ; F7
              RSTs38H      == ir1  ;     // RST 38H      ; FF
 
wire c_call  =  CALLsC_NN    == ir1   |  //XX XX  (-- --SP) <- PC, PC<-NN
                CALLsM_NN    == ir1   |
                CALLsNC_NN   == ir1   |
                CALLsNZ_NN   == ir1   |
                CALLsPE_NN   == ir1   |
                CALLsPO_NN   == ir1   |
                CALLsP_NN    == ir1   |
                CALLsZ_NN    == ir1   ;
 
 
//  these are executed exec(ossp) ; op1(ossp); op2(ifnn p<-n+1)goto if2 
assign   call = CALLsNN      == ir1 |  //    XX XX  (-- --SP) <- PC, PC<-NN
                c_call & br_test8t  ;  //    XX XX  (-- --SP) <- PC, PC<-NN
 
wire c_ret =  RETsC        == ir1 & br_test8t | //      RET C        ; D8  PC <- (SP++ ++)
              RETsM        == ir1 & br_test8t | //      RET M        ; F8  PC <- (SP++ ++)
              RETsNC       == ir1 & br_test8t | //      RET NC       ; D0  PC <- (SP++ ++)
              RETsNZ       == ir1 & br_test8t | //      RET NZ       ; C0  PC <- (SP++ ++)
              RETsP        == ir1 & br_test8t | //      RET P        ; F0  PC <- (SP++ ++)
              RETsPE       == ir1 & br_test8t | //      RET PE       ; E8  PC <- (SP++ ++)
              RETsPO       == ir1 & br_test8t | //      RET PO       ; E0  PC <- (SP++ ++)
              RETsZ        == ir1 & br_test8t ; //      RET Z        ; C8  PC <- (SP++ ++)
 
assign   ret =RET          == ir1 |             //      RET          ; C9  PC <- (SP++ ++)
              ED_RETN      == {ir[9:6],ir[2:0]}| // compair with {ir[7:6],ir[2:0]} and !reti
              c_ret & br_test8t  ;
 
assign   ioi = INsA_6N7     == ir1 |               //      IN A,(N)     ; DB XX    A<-(Nio) 
               ED_INsREG_6C7 == {ir[9:6],ir[2:0]} ;// really (BCio)
 
assign   ioo  = OUTs6N7_A    == ir1 |             //      OUT (N),A    ; D3 XX     A-> (Nio)
                ED_OUTs6C7_REG == {ir[9:6],ir[2:0]} ;
 
// execution of     |  exec   |   rpt_t     |  op3     |
// repeats          |         |(if done if2 |goto rpt_t|
// rel to mem_state | of BC-- |  os         | of BC--  |
// rpt test must allow for interrupts - pc and BC must be properly rolled back 
 
assign   blk_mv = ED_LDI  == ir1 | //  (DE++) <= (HL++) , BC-- 
                  ED_LDD  == ir1 | //  (DE--) <= (HL--) , BC--
                  ED_LDIR == ir1 | //  (DE++) <= (HL++) , BC-- Repeat 
                  ED_LDDR == ir1 ; //  (DE--) <= (HL--) , BC-- Repeat 
 
 
// execution of     |  exec   |  op3     |    rpt_t     |
// repeats          | goto op3|goto rpt_t|  if done if2 |
// rel to mem_state | of BC-- | nop      |  else of BC--|
//
// rpt test must allow for interrupts - pc and BC must be properly rolled back 
// lets goto a special state for this - 
//  bj -think - pc must be rolled back in any case - how does that happen? notes for main_state
//    already have this being done on MEM_INT1   --- on reflection, BC is correct  - post decrement
//    we tested the decremented value.   Mental test here ---   start with 1 - get 0 stop.
//    (um states explicitly that if you start with 0 you get 64k)
//    start with 2 get interrupt  (we now have 1) interrupt with 1 in bc  ok.
//
assign   blk_cmp = ED_CPI  == ir1 | //  CPI  ; ED A1    A - (HL++) , BC--
                   ED_CPD  == ir1 | //  CPD  ; ED A9    A - (HL--) , BC--
                   ED_CPIR == ir1 | //  CPIR ; ED B1    A - (HL++) , BC-- repeat if(|B
                   ED_CPDR == ir1 ; //  CPDR ; ED B9    A - (HL--) , BC-- repeat if(|B
 
 
 
 
assign blk_in = ED_INI  == ir1 | // INI  ; ED A2   (HL++) <- (Cio) , B--;
                ED_IND  == ir1 | // IND  ; ED AA   (HL--) <- (Cio) , B--
                ED_INIR == ir1 | // INIR ; ED B2   (HL++) <- (Cio) , B-- repeat if(|B)
                ED_INDR == ir1 ; // INDR ; ED BA   (HL--) <- (Cio) , B-- repeat if(|B)
 
 
 
assign  blk_out = ED_OUTI  == ir1 | // OUTI  ED A3  (Cio)  <-(HL++) , B--
                  ED_OUTD  == ir1 | // OUTD  ED AB  (Cio)  <-(HL--) , B--
                  ED_OTIR  == ir1 | // OTIR  ED B3  (Cio)  <-(HL++) , B--  rpt if(|B)
                  ED_OTDR  == ir1 ; // OTDR  ED BB  (Cio)  <-(HL--) , B--  rpt if(|B)
 
 
assign  blk_rpt =  ED_LDIR == ir1 | //  (DE++) <= (HL++) , BC-- Repeat 
                   ED_LDDR == ir1 | //  (DE--) <= (HL--) , BC-- Repeat 
                   ED_CPIR == ir1 | //  CPIR ; ED B1    A - (HL++) , BC-- repeat if(|B
                   ED_CPDR == ir1 | //  CPDR ; ED B9    A - (HL--) , BC-- repeat if(|B
                   ED_INIR == ir1 | // INIR ; ED B2   (HL++) <- (Cio) , B-- repeat if(|B)
                   ED_INDR == ir1 | // INDR ; ED BA   (HL--) <- (Cio) , B-- repeat if(|B)
                   ED_OTIR == ir1 | // OTIR  ED B3  (Cio)  <-(HL++) , B--  rpt if(|B)
                   ED_OTDR == ir1 ; // OTDR  ED BB  (Cio)  <-(HL--) , B--  rpt if(|B)
 
assign   blk_inc = ED_LDI  == ir1  | //  (DE++) <= (HL++) , BC-- 
                   ED_LDIR == ir1  | //  (DE++) <= (HL++) , BC-- Repeat 
                   ED_CPI  == ir1  | //  CPI  ; ED A1    A - (HL++) , BC--
                   ED_CPIR == ir1  | //  CPIR ; ED B1    A - (HL++) , BC-- repeat if(|B
                   ED_INI  == ir1  | // INI  ; ED A2   (HL++) <- (Cio) , B--;
                   ED_INIR == ir1  | // INIR ; ED B2   (HL++) <- (Cio) , B-- repeat if(|B)
                   ED_OUTI  == ir1 | // OUTI  ED A3  (Cio)  <-(HL++) , B--
                   ED_OTDR  == ir1 ; // OTDR  ED BB  (Cio)  <-(HL--) , B--  rpt if(|B)
 
 
wire   push    =  PUSHsAF   == ir1 | //      PUSH AF      ; F5   (-- --SP) <- AF
                  PUSHsBC   == ir1 | //      PUSH BC      ; C5   (-- --SP) <- BC
                  PUSHsDE   == ir1 | //      PUSH DE      ; D5   (-- --SP) <- DE
                  PUSHsHL   == ir1 ; //      PUSH HL      ; E5   (-- --SP) <- HL
 
 
 
wire   pop =      POPsAF    == ir1 | //      POP AF       ; F1   AF<- (SP++ ++)  
                  POPsBC    == ir1 | //      POP BC       ; C1   BC<- (SP++ ++)  
                  POPsDE    == ir1 | //      POP DE       ; D1   DE<- (SP++ ++)  
                  POPsHL    == ir1 ; //      POP HL       ; E1   HL<- (SP++ ++) 
 
assign use_sp = push | pop | call | ret;
assign ofos = cb_mem | of8 | of16 | os8 | os16 | rmw8 | xchng16 | jmp | call | ret |
                 ioi  | ioo | blk_mv | blk_cmp | blk_in | blk_out | push | pop         ;
assign exec_if = mem_exec & !ofos;
 
 
// wires below can be used to select os data - with the addition of 
// ED_LDs6NN7_REG = {ir[7:6],ir[3:0]}; //REG = BC,DE,HL,SP - These cannot cause
// hazards as ir2 is executed as ED is decoded.
// so what???  include them anyway....   Hazard detection is disabled after ir2 is executed. kiss
//
wire os_a  =  LDs6BC7_A    == ir1 |  //      LD (BC),A    ; 02
              LDs6DE7_A    == ir1 |  //      LD (DE),A    ; 12
              LDs6HL7_A    == ir1 |  //      LD (HL),A    ; 77
              LDs6NN7_A    == ir1 |  //      LD (NN),A    ; 32 XX XX
              PUSHsAF      == ir1 |
              OUTs6N7_A    == ir1 |
              ED_OUTs6C7_REG ==  {ir[7:6],ir[2:0] && REG8_A == ir[5:3]} ;
 
wire os_b = LDs6HL7_B    == ir1 |  //      LD (HL),B    ; 70
            PUSHsBC      == ir1 |      //      PUSH BC
            ED_LDs6NN7_REG == {ir[7:6],ir[3:0] && DBL_REG_BC == ir[5:4] |
            ED_OUTs6C7_REG ==  {ir[7:6],ir[2:0] && REG8_B == ir[5:3]} ;
 
wire os_c = LDs6HL7_C    == ir1  |  //      LD (HL),C    ; 71
            ED_OUTs6C7_REG ==  {ir[7:6],ir[2:0] && REG8_C == ir[5:3]} ;
wire os_d = LDs6HL7_D    == ir1 |  //      LD (HL),D    ; 72
            PUSHsDE      == ir1 |      //      PUSH DE
            ED_LDs6NN7_REG == {ir[7:6],ir[3:0] && DBL_REG_DE == ir[5:4] |
            ED_OUTs6C7_REG ==  {ir[7:6],ir[2:0] && REG8_D == ir[5:3]} ;
 
 
wire os_e = LDs6HL7_E    == ir1  |  //      LD (HL),E    ; 73
            ED_OUTs6C7_REG ==  {ir[7:6],ir[2:0] && REG8_E == ir[5:3]} ;
 
wire os_h = LDs6HL7_H    == ir1 |  //      LD (HL),H    ; 74
            LDs6NN7_HL   == ir1 |            //      LD (NN),HL   ; 22 XX XX
            ED_LDs6NN7_REG == {ir[7:6],ir[3:0] && DBL_REG_HL == ir[5:4] |
            ED_OUTs6C7_REG ==  {ir[7:6],ir[2:0] && REG8_H == ir[5:3]} ;
wire os_l = LDs6HL7_L    == ir1  |  //      LD (HL),L    ; 75
            ED_OUTs6C7_REG ==  {ir[7:6],ir[2:0] && REG8_L == ir[5:3]} ;
 
wire os_sp = ED_LDs6NN7_REG == {ir[7:6],ir[3:0] && DBL_REG_SP == ir[5:4];
 
 
// does not include extension stuff as we are mostly looking for hazards here
// course we do use these terms to build more decodes
//
wire  opadr_bc  =  LDsA_6BC7  == ir1 | LDs6BC7_A == ir1;
wire  opadr_de  =  LDsA_6DE7  == ir1 | LDs6DE7_A == ir1;
wire  opadr_hl  =  LDsB_6HL7  == ir1 | ORs6HL7    == ir1 | LDs6HL7_B == ir1 |
                   LDsD_6HL7  == ir1 | LDsC_6HL7  == ir1 | LDs6HL7_C == ir1 |
                   LDsH_6HL7  == ir1 | LDsE_6HL7  == ir1 | LDs6HL7_D == ir1 |
                   ADDsA_6HL7 == ir1 | LDsL_6HL7  == ir1 | LDs6HL7_E == ir1 |
                   SUBs6HL7   == ir1 | LDsA_6HL7  == ir1 | LDs6HL7_H == ir1 |
                   ANDs6HL7   == ir1 | ADCsA_6HL7 == ir1 | LDs6HL7_L == ir1 |
                   XORs6HL7   == ir1 | SBCs6HL7   == ir1 | CPs6HL7   == ir1 ;
 
assign  use_a = os_a;
assign  use_b = os_b  | opadr_bc;
assign  use_c = os_c  | opadr_bc;
assign  use_d = os_d  | opadr_de;
assign  use_e = os_e  | opadr_de;
assign  use_h = os_h  | opadr_hl;
assign  use_l = os_l  | opadr_hl;
 
 
 
assign   use_flags = c_jmp8 | c_jmp4 | c_call | c_ret;
 
 
 
wire bc_eq0 = beq0 & ceq0;
assign rpt_blk_mv = (blk_mv_reg )  & !bc_eq0     |
                    (blk_cmp_reg) & !bc_eq0 & (nn[7:0] != 8'h0)  |
                    (blk_in_reg | blk_out_reg) & !b_eq0 ;
 
 
 
 
 
 
 
//  BASIC ARCHITECTURE OF THIS FILE   pc  and sp not shown, but are inputs to src mux.
//                    _____           and may be updated from adder output.
//                   |     |
//                   |     |          pc-1 register is required to implement relative jumps.
//                   |     |                     
//      _____        |lit  |      |\             
//     |     |       |     |      |  \           
//     |     |       |src2 |      |    \          _____          _____ 
//     |     |       |     |----->|     |        |     |        |     |
//     |src  |       |_____|      |adder|------->|     |        |     |
//     |mux  |                    |     |        |     |        |     |
//     |     |------------------->|    /         |2/1  |------->|wb   |
//     |     |              |     |  /           |mux  |        |adr  |
//     |_____|              |     |/             |     |        |     |
//                           ------------------->|     |        |     |
//                                               |_____|        |_____|
//
// There was a time when I thought we might use wb_add  (or a copy) as a source for the 
// src mux ( thought I might need to save less state that way )
// seems like most state is needed in any case -- so this way I don't have to worry about
// multiple loads on wb_adr..
//
//
wire src_sp = (mem_exec) ? use_sp : push_reg | pop_reg | call_reg & mem_op1 | ret_reg & mem_op1;
 
wire src_pc = mem_if1 | mem_if2 | mem_exec & !exec_of;
wire src_nn = ir1 == LDsA_6NN7   & mem_exec   |  
              ir1 == LDsHL_6NN7  & mem_exec   |
              ir1 == LDs6NN7_A   & mem_exec   |
              ir1 == LDs6NN7_HL  & mem_exec   |
              ir1 == jmp         & mem_exec   |
                     call_reg    & mem_op2    |
              ir1 == INsA_6N7    & mem_exec   |
              ir1 == OUTs6N7_A   & mem_exec   |
 
//  don't forget that hl source can be modified by prefix
wire src_hl =  ir1 ==  LDsB_6HL7  & mem_exec |      //LD B,(HL)    ; 46
               ir1 ==  LDsD_6HL7  & mem_exec |      //LD D,(HL)    ; 56
               ir1 ==  LDsH_6HL7  & mem_exec |      //LD H,(HL)    ; 66
               ir1 ==  ADDsA_6HL7 & mem_exec |      //ADD A,(HL)   ; 86
               ir1 ==  SUBs6HL7   & mem_exec |      //SUB (HL)     ; 96
               ir1 ==  ANDs6HL7   & mem_exec |      //AND (HL)     ; A6
               ir1 ==  ORs6HL7    & mem_exec |      //OR (HL)      ; B6
               ir1 ==  LDsC_6HL7  & mem_exec |      //LD C,(HL)    ; 4E
               ir1 ==  LDsE_6HL7  & mem_exec |      //LD E,(HL)    ; 5E
               ir1 ==  LDsL_6HL7  & mem_exec |      //LD L,(HL)    ; 6E
               ir1 ==  LDsA_6HL7  & mem_exec |      //LD A,(HL)    ; 7E
               ir1 ==  ADCsA_6HL7 & mem_exec |      //ADC A,(HL)   ; 8E
               ir1 ==  SBCs6HL7   & mem_exec |      //SBC (HL)     ; 9E
               ir1 ==  XORs6HL7   & mem_exec |      //XOR (HL)     ; AE
               ir1 ==  CPs6HL7    & mem_exec |      //CP (HL)      ; BE
               ir1 ==  LDs6HL7_N  & mem_exec |      //LD (HL),N    ; 36 XX
               ir1 ==  LDs6HL7_A  & mem_exec |      //LD (HL),A    ; 77
               ir1 ==  LDs6HL7_B  & mem_exec |      //LD (HL),B    ; 70
               ir1 ==  LDs6HL7_C  & mem_exec |      //LD (HL),C    ; 71
               ir1 ==  LDs6HL7_D  & mem_exec |      //LD (HL),D    ; 72
               ir1 ==  LDs6HL7_E  & mem_exec |      //LD (HL),E    ; 73
               ir1 ==  LDs6HL7_H  & mem_exec |      //LD (HL),H    ; 74
               ir1 ==  LDs6HL7_L  & mem_exec |      //LD (HL),L    ; 75
               // rmw 8 types
               ir1 ==  INCs6HL7   & mem_exec |      //INC (HL)     ; 34
               ir1 ==   DECs6HL7  & mem_exec |       //DEC (HL)     ; 35
               blk_mv             & mem_exec |
               blk_cmp            & mem_exec |
               blk_out            & mem_exec |
               ir1[2:0]==CB_MEM & 
                 ir[9:8] == 2'b01 & mem_exec |
 
               blk_mv_reg         & mem_op2  | 
               blk_cmp_reg        & mem_op2  | 
               blk_out_reg        & mem_op2 
                // all block moves
 
wire src_de  = ir1 ==  LDsA_6DE7 & mem_exec |
               ir1 ==  LDs6DE7_A & mem_exec   ;
 
 
wire src_bc =  ir1 ==  LDsA_6BC7 & mem_exec |
               ir1 ==  LDs6BC7_A & mem_exec ;
 
wire inc 
 
assign src_mux =   {16{ src_sp  }} & sp |
                   {16{ src_pc  }} & pc |
                   {16{ src_nn  }} & nn |
                   {16{ src_hl  }} & hl |
                   {16{ src_de  }} & de |
                   {16{ src_bc  }} & bc   :
 
assign src2    = {16{ inc }}    & 16'h0001        |
                 {16{ dec }}    & 16'hffff        |
                 {16{ rel_jmp}} & {8{nn7},nn[7:0]};
 
 
assign alu     = src2 + src_mux;                 
 
assign mux21 =  pre_inc_dec ? alu : src_mux; 
assign wb_rdy = !wb_cyc | wb_ack;
 
//-------1---------2---------3--------State Machines-------6---------7---------8---------9--------0
 
 
wire exec_ir1 = (MEM_EXEC == mem_state);
always @(posedge clk or posedge rst)
    if (rst)
    begin
        of16_reg    <= 1'b0;
        os16_reg    <= 1'b0; 
        rmw8_reg    <= 1'b0; 
        push_reg    <= 1'b0; 
        pop_reg     <= 1'b0;
        call_reg    <= 1'b0; 
        ret_reg     <= 1'b0; 
        blk_mv_reg  <= 1'b0;
        blk_cmp_reg <= 1'b0;
        blk_in_reg  <= 1'b0; 
        blk_out_reg <= 1'b0;
        blk_rpt_reg <= 1'b0;
        blk_inc_reg <= 1'b0;
        src_nn_reg  <= 1'b0;
        src_hl_reg  <= 1'b0;
    end
    else if (exec_ir1)
    begin
        of16_reg    <= of16   ;
        os16_reg    <= os16   ; 
        rmw8_reg    <= rmw8   ; 
        push_reg    <= push   ; 
        pop_reg     <= pop    ;
        call_reg    <= call   ; 
        ret_reg     <= ret    ; 
        xchng16_reg <= xchng16 ;
        blk_mv_reg  <= blk_mv  ;
        blk_cmp_reg <= blk_cmp;
        blk_in_reg  <= blk_in ;
        blk_out_reg <= blk_out;
        blk_rpt_reg <= blk_rpt;
        blk_inc_reg <= blk_inc;
        src_nn_reg  <= src_nn ;
    end
 
// first cut at the main state machine. 
//      make one hot to speed up decoding  ?   leaning that way...  but no big deal till 
//      physical.
//      MEM_HALT  ---  kind of silly to sit here and wait for interrupt - but ok  gotta do something.
//                    
//      Lot of Issues here Interrupts  ( during block moves - roll back pc )
//                         hazards
//                         halt
//      3/17/2004 on first time through the ddcb and fdcb prefix operations were wrong - 
//       in fact fdfdcb is not handled as It appears it "should be".  
 
//               of16         os16    rmw8         push-pop               call
//
//MEM_EXEC      of_adr     os_adr++  of_adr   sp <=pop?++adr :--adr     --sp<=pc
//MEM_OP1       of_adr++   os_adr++  os_adr   sp <=pop?++adr :--adr     --sp<=pc<=NN
//                <IF2        <IF2   <IF2       <IF2                       <IF1
//
//              ioi           ioo
//MEM_IF2 
//MEM_EXEC      iof           ios   
//MEM_OP1 
 
 
 
//
//           ret         blk_mv       blk_cmp      blk_in blk_o      int          xchng16
//MEM_IDLE
//MEM_HALT
//MEM_IF1 
//MEM_IF2 
//MEM_EXEC sp<=++adr    of_6src7       of6src7    iof      of         iof              of
//                     > RPT_T         >OP3      >RPT_T   >RPT+T
//MEM_OP1                                                                           os
//MEM_OP2                                                                           of
//MEM_OP3              of RPT_T       >RPT_T        iof      of                       os >IF2 
//MEM_RPT_T           os done?         done?      os done? ios done?
//                     IF2:OP3        >IF2:of>OP3  IF2:OP3  IF2:OP3
//
//
//MEM_INT1                                                             (--sp)<=pcH
//MEM_INT2                                                             (--sp)<=PCL
//                                                                      pc<=I,n >IF1
//MEM_INT3                                                             of_n
//MEM_INT4                                                             of_nn
//MEM_INT5                                                             pc<=nn
 
wire  goto_op1 = (of16 |os16 | rmw8 | xchng16| call | ret );
wire  goto_op2 =  xchng16_reg;
wire  goto_rpt_t =  blk_mv | blk_in | blk_out;
wire  goto_op3   = blk_cmp;
wire  blk_mv_rpt = 
 
 
always @(posedge clk or posedge rst)
    if (rst)  mem_state <= MEM_IDLE;
    else  if (wb_rdy)                   // wb rdy = wb_idle | wb_ack
    begin
        case (mem_state)
            MEM_IDLE:             mem_state <= MEM_IF1
            MEM_HALT:             mem_state <= MEM_HALT   // stay here until interrupt or reset
            MEM_IF1               mem_state <= MEM_IF2
            MEM_IF2 :             mem_state <= MEM_EXEC;
            MEM_EXEC :
                if (int)          mem_state   <= MEM_INT1;
                else if(halt)     mem_state   <= MEM_HALT;
                else if (ir1_val) 
                begin
                    if(mem_hazard) mem_state <= MEM_IF1; // restart i pipe
                    else if(reg_hazard) mem_state <= MEM_IF2; // wait for inst execution
                    else if(jmp )       mem_state <= MEM_IF1;
                    else if(goto_op1)   mem_state <= MEM_OP1;
                    else if(of8 | os8)  mem_state <= MEM_IF1;
                    else if(goto_rpt_t) mem_state <= MEM_RPT_T;
                    else if(goto_op3)   mem_state <= MEM_OP3;
                    else                mem_state <= MEM_EXEC;
                end    
            MEM_OP1 :
                if (xchang16   )  mem_state <= MEM_OP2;
                else              mem_state <= MEM_IF2;
            MEM_OP2 :             mem_state <= MEM_OP3;
            MEM_OP3 :
                if (xchng16_reg)  mem_state <= MEM_IF2;
                else              mem_state <= MEM_RPT_T;
            MEM_RPT_T :
                if (!rpt_blk_mv)  mem_state <= MEM_IF2;
                else if (int)     mem_state <= MEM_INT1;
                else
            MEM_INT1:             mem_state <= MEM_INT2;
            MEM_INT2:             mem_state <= MEM_INT3;
            MEM_INT3:             mem_state <= MEM_INT4;
            MEM_INT4:             mem_state <= MEM_INT5;
            MEM_INT5:             mem_state <= MEM_IF1;    
        endcase
    end
//  some assignemnts to save on virtual paper
//
assign mem_idle = MEM_IDLE  ==mem_state;
assign mem_halt = MEM_HALT  ==mem_state;
assign mem_if1  = MEM_IF1   ==mem_state;
assign mem_if2  = MEM_IF2   ==mem_state;
assign mem_exec = MEM_EXEC  ==mem_state;
assign mem_op1  = MEM_OP1   ==mem_state;
assign mem_op2  = MEM_OP2   ==mem_state;
assign mem_op3  = MEM_OP3   ==mem_state;
assign mem_rpt_t= MEM_RPT_T == mem_state;
assign mem_int1 = MEM_INT1  ==mem_state;
assign mem_int2 = MEM_INT2  ==mem_state;
assign mem_int3 = MEM_INT3  ==mem_state;
assign mem_int4 = MEM_INT4  ==mem_state;
assign mem_int5 = MEM_INT5  ==mem_state;
 
 
assign  any_os =    os8 & mem_exec        | 
                    os16 & mem_exec       | 
                    call & mem_exec       | 
                    push & mem_exec       |
                    os16_reg & mem_op1    |
                    rmw8_reg & mem_op1    | 
                    xchng16_reg & mem_op1 |
                    xchng16_reg & mem_op3 |
                    call_reg & mem_op1    | 
                    blk_mv_reg & mem_rpt_t|
                    blk_in_reg & mem_rpt_t| 
                    int_reg  &  mem_int1  |        
                    int_reg  & mem_int2    ;
 
 
assign any_ios = ioo & mem_exec | blk_out_reg & mem_rpt_t;
assign any_iof = ioi & mem_exe  | blk_in_reg & mem_op3; 
 
 
 
//  program counter 
wire if_pinc = mem_if1 | mem_if2 | exec_if; 
always @(posedge clk or posedge rst)
    if (rst)  pc <= 16'h0
    else if if_pinc pc <= alu;
 
 
//-------------------------- memory interface stuff ----------------------------
 
 
// --  wb_adr
always @(posedge clk) if (wb_rdy) wb_adr <= mux21
 
// --  wb_we; 
 
always @(posedge clk or posedge rst)
    if (rst)         wb_we <= 1'b0;
    else if (wb_rdy) wb_we <= (any_os | any_ios);
// --  wb_cyc
 
wire no_wb_start = mem_idle | mem_halt | mem_op3 & blk_cmp_reg | mem_op1 & rmw_reg;
always @(posedge clk or posedge rst)
    if (rst)         wb_cyc <= 1'b0;
    else if (wb_rdy) wb_cyc <= !no_wb_start
// --  wb_stb; 
 
always @(posedge clk or posedge rst)
    if (rst)         wb_cyc <= 1'b0;
    else if (wb_rdy) wb_cyc <= !no_wb_start
 
 
// --  wb_lock;
 
always @(posedge clk or posedge rst)
    if (rst)         wb_lock <= 1'b0;
    else if (wb_rdy)
    begin
        if (mem_exec & rmw)    wb_lock <= 1'b1;
        if (mem_if2 & rmw_reg) wb_lock <= 1'b0;
    end
 
 
// --  wb_tga_io
always @(posedge clk or posedge rst)
    if (rst)         wb_tga_io <= 2'b0;
    else if (wb_rdy)
    begin
        if (any_iof | any_ios)    wb_tga_io <= TAG_IO;
        else if (mem_exec & int ) wb_tga_io <= TAG_INT;
        else                      wb_tga_io <= 2'b0 
    end
 
 
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.