URL
https://opencores.org/ocsvn/vg_z80_sbc/vg_z80_sbc/trunk
Subversion Repositories vg_z80_sbc
[/] [vg_z80_sbc/] [trunk/] [rtl/] [z80_memstate2.v] - Rev 36
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////////////////////////// // // // file name: memstate2.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 -- // the interaction between these sequencers was becomming harder to track than a single // state macine. Thus - this file is getting re-worked. I will call it memstate2 (at least // for awhile) as I wish to keep the old file around. I want to show (in the state machine // logic) what the next memory operation is.... guess the best method consistent with my // documentation practices is to define a register (mem_op) = { if, wb_we_o, wb_cyc_o }. // This will require auxillary logic for computing the address --- but most of the decodes // required will be there anyway. // On further reflection, I think I will bite-the-bullet and use an always to define next_state. // I don't like to use always to define wires, but I also want to document the setting of // exec_ir2 in the same place - that is 3 different things. // // 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: z80_memstate2.v,v 1.1 2008-12-01 02:00:10 hharte Exp $ // // $Date: 2008-12-01 02:00:10 $ // $Revision: 1.1 $ // $Author: hharte $ // $Locker: $ // $State: Exp $ // // Change History: // $Log: not supported by cvs2svn $ // Revision 1.8 2007/10/12 17:08:43 bporcella // added fix for IN bug found by howard // // Revision 1.7 2007/10/02 20:25:12 bporcella // fixed bugs and augmented instruction test. // ex de hl bug fixed thanks Howard Harte // ret condition (ret not taken bug) thanks - Stephen Warren // // Revision 1.6 2004/06/03 20:29:35 bporcella // some fixes found in synthesis // // Revision 1.5 2004/05/27 14:23:36 bporcella // Instruction test (with interrupts) runs!!! // // Revision 1.4 2004/05/21 02:51:25 bporcella // inst test got to the worked macro // // Revision 1.3 2004/05/18 22:31:21 bporcella // instruction test getting to final stages // // Revision 1.2 2004/05/13 14:58:53 bporcella // testbed built and verification in progress // // Revision 1.1 2004/04/27 21:27:13 bporcella // first core build // // Revision 1.8 2004/04/19 19:13:28 bporcella // real lint problems pretty much fixed -- need another look - but need to get on to other things first // // Revision 1.7 2004/04/19 05:09:11 bporcella // fixed some lint problems -- // // Revision 1.6 2004/04/18 18:50:09 bporcella // fixed some lint problems -- // // Revision 1.5 2004/04/17 15:18:02 bporcella // 4th lint try // Miha claims reports are now correct // // Revision 1.4 2004/04/16 18:16:57 bporcella // try lint // // Revision 1.3 2004/04/16 17:06:54 bporcella // no code change - added a comment and test lint // // Revision 1.2 2004/04/16 16:21:04 bporcella // no code change - added a comment and test lint // // Revision 1.1.1.1 2004/04/13 23:50:19 bporcella // import first files // // // //-------1---------2---------3--------Module Name and Port List------7---------8---------9--------0 module z80_memstate2(wb_adr_o, wb_we_o, wb_cyc_o, wb_stb_o, wb_tga_o, wb_dat_o, exec_ir2, exec_decbc, exec_decb, ir1, ir2, ir1dd, ir1fd, ir2dd, ir2fd, nn, sp, upd_ar, upd_br, upd_cr, upd_dr, upd_er, upd_hr, upd_lr,upd_fr, beq0, ceq0, ar, fr, br, cr, dr, er, hr, lr, intr, ixr, iyr, wb_dat_i, wb_ack_i, wb_clk_i, int_req_i, add16, alu8_out, adr_alu, blk_mv_upd_hl, blk_mv_upd_de, sh_alu, bit_alu, rst_i ); //-------1---------2---------3--------Output Ports---------6---------7---------8---------9--------0 // mod only to checkout lint // mod again for lint check -- first check pretty wierd // 3rd lint try // 4th lint try output [15:0] wb_adr_o; output wb_we_o; output wb_cyc_o; output wb_stb_o; //output wb_lock; // bit set and clear insts should be atomic - could matter sometime output [1:0] wb_tga_o; output [7:0] wb_dat_o; // from nn output [15:0] adr_alu; // 4/18/2004?? why? 5/20 to update hl on // block moves silly output blk_mv_upd_hl; output blk_mv_upd_de; output exec_ir2; output [9:0] ir1, ir2; output ir1dd, ir2dd; output ir1fd, ir2fd; output [15:0] nn; output [15:0] sp; output exec_decbc, exec_decb; //-------1---------2---------3--------Input Ports----------6---------7---------8---------9--------0 input upd_ar, upd_br, upd_cr, upd_dr, upd_er, upd_hr, upd_lr,upd_fr; input beq0, ceq0; input [7:0] ar, fr, br, cr, dr, er, hr, lr, intr; input [15:0] ixr, iyr; input [7:0] wb_dat_i; input wb_ack_i, wb_clk_i, rst_i; input int_req_i; input [15:0] add16; // ir2 execution engine output for sp updates input [7:0] alu8_out; input [7:0] sh_alu; // rmw shifts input [7:0] bit_alu; //-------1---------2---------3--------Parameters-----------6---------7---------8---------9--------0 `include "opcodes.v" // states of the main memory sequencer parameter TAG_IO = 2'b01, // need to review general wb usage to undrstand how best to TAG_INT = 2'b10; // document this. // 12na // 1 is ir1 2 is ir2 n is nn gets memory a is activate ir2 parameter IPIPE_NOP = 4'b0000, // guess I could define single bits and add them up IPIPE_A2 = 4'b0001, // would keep from getting lint bitching -- but heck IPIPE_ENN = 4'b0010, // I'm married -> an expert at ignoring such stuff :-) IPIPE_ENNA2 = 4'b0011, IPIPE_EN2 = 4'b0100, IPIPE_EN2A2 = 4'b0101, IPIPE_ENNEN2 = 4'b0110, IPIPE_ENNEN2A2 = 4'b0111, IPIPE_EN1 = 4'b1000, IPIPE_EN1A2 = 4'b1001, IPIPE_BOGUS = 4'b1010, // no reason (yet) to load both n and ir1 IPIPE_BOUS2 = 4'b1011, IPIPE_EN12 = 4'b1100, IPIPE_EN12A2 = 4'b1101, IPIPE_BOGUS3 = 4'b1110, IPIPE_BOGUS4 = 4'b1111; // well at first cut I tried to make this 2 state macines both less than 16 states. // this is 56 states at first cut. Assignemnt is subject to change. // 10/11/2007 I really need some comments about the states. Lots of stuff here to // pick up from scratch. // ------ mem state decoder state machine states -------------------------------- parameter DEC_IDLE = 6'h00, DEC_HALT = 6'h01, // note that we can service interrupts while "halted" DEC_IF1 = 6'h02, // start the instruction pipe with MEM_IFPP1 DEC_IF2 = 6'h03, // store the active read in ir1 and start another MEM_IFPP1 DEC_IF2A = 6'h04, // start a MEM_IFPP1 (but ir1 already has next instruction) DEC_EXEC = 6'h05, // PRIME ir1 decode state. decode first byte of EACH inst here DEC_CB = 6'h06, // PRIME decode yields I1_CB DEC_DDFD = 6'h07, // PRIME decode yields I1_DDFD (DD or FD group) DEC_ED = 6'h08, // PRIME decode yields I1_ED DEC_EDNN1 = 6'h09, // Immediate states DEC_EDNN2 = 6'h0a, DEC_EDRD1 = 6'h0b, DEC_EDRD2 = 6'h0c, DEC_EDWR = 6'h0d, DEC_EDBCP1 = 6'h0e, DEC_EDBCP2 = 6'h0f, DEC_EDBCP3 = 6'h10, DEC_EDBIN1 = 6'h11, DEC_EDBIN2 = 6'h12, DEC_EDBIN3 = 6'h13, DEC_EDBOUT1 = 6'h14, DEC_EDBOUT2 = 6'h15, DEC_EDBOUT3 = 6'h16, DEC_EDBMV1 = 6'h17, DEC_EDBMV2 = 6'h18, DEC_EDBMV3 = 6'h19, DEC_N = 6'h1a, // PRIME decode yields DEC_N (next byte is immediate data byte) DEC_NIN = 6'h1b, DEC_NN = 6'h1c, // PRIME decode yields DEC_NN (2 immediate data bytes follow) DEC_NNCALL1 = 6'h1d, DEC_NNCALL2 = 6'h1e, DEC_NNOS1 = 6'h1f, DEC_NNOS2 = 6'h20, DEC_NNOS3 = 6'h21, DEC_NNOF1 = 6'h22, DEC_NNOF2 = 6'h23, DEC_NNOF3 = 6'h24, DEC_NNOF4 = 6'h25, DEC_DDOS = 6'h26, DEC_DDOF = 6'h27, DEC_OF = 6'h28, // PRIME decode yields I1_OF DEC_POP = 6'h29, // PRIME decode yields I1_POP DEC_PUSH = 6'h2a, // PRIME decode yields I1_PUSH DEC_RMW = 6'h2b, // PRIME decode yields I1_RMW DEC_RMW2 = 6'h2c, DEC_CBM = 6'h2d, DEC_PFxCB = 6'h2e, DEC_PFxCB2 = 6'h2f, DEC_PFxCB3 = 6'h30, DEC_PFxCB4 = 6'h31, DEC_INT1 = 6'h32, DEC_INT2 = 6'h33, DEC_INT3 = 6'h34, DEC_INT4 = 6'h35, DEC_INT5 = 6'h36, DEC_RET = 6'h37, // PRIME decode yields DEC_NNJMP = 6'h38, DEC_DDN = 6'h39, DEC_RET2 = 6'h3a, DEC_EXSPHL = 6'h3b, DEC_RMWDD1 = 6'h3c, DEC_RMWDD2 = 6'h3d, DEC_INT6 = 6'h3e ; // initial decode assignemnts. These assignemens are made to wires on an initial decode // to help document next state transitions parameter I1_CB = 4'h0, I1_DDFD = 4'h1, I1_ED = 4'h2, I1_JMP = 4'h3, I1_N = 4'h4, I1_NN = 4'h5, I1_OF = 4'h6, I1_OS = 4'h7, I1_POP = 4'h8, I1_PUSH = 4'h9, I1_RET = 4'ha, I1_RMW = 4'hb, I1_RST = 4'hc, I1_R2R = 4'hd, I1_JMPR = 4'he, I1_HALT = 4'hf; // A note here on the choices of mnemonics..... in general, the target registers of // memory ops are specified by an instruction register (ir1 for stores ir2 for loads). // so Menomics in general are specifying the address source. However, there are exceptions. // parameter MEM_NOP = 5'h00, MEM_IFPP1 = 5'h01, MEM_OS1 = 5'h02, // only invoked on I1 OS multiple address sources and data sources MEM_OF1 = 5'h03, // Address from HL unless LD A,(BC) or LD A,(DE) (used for rmw) MEM_OFSP = 5'h04, // works for both POP and RET MEM_OSSP = 5'h05, // if DEC_EXEC op from ir1 else msb nn (implies we store from lsb nn) // used in CALL also. MEM_OFIXpD = 5'h06, // used for prefix op fetches - all single bytes MEM_OSIXpD = 5'h07, // data source is same as MEM_OS1 MEM_OSADR = 5'h08, // used (at lesat) for prefixed rmw -- perhaps others. MEM_CALL = 5'h09, // pc<=nn, nn<=pc, wb_adr_o<=sp OS MEM_OSNN = 5'h0a, // if DEC_EXEC op from ir1 else msb nn MEM_OFNN = 5'h0b, // striaghtfoward MEM_OFADRP1 = 5'h0c, // used (at least) when double ops above MEM_OSADRP1 = 5'h0d, // "" "" "" MEM_RST = 5'h0e, // MEM_REL2PC = 5'h0f, // special address transfer for jmp rel MEM_JMPHL = 5'h10, // another special jump transfer MEM_IFNN = 5'h11, // used by call and return MEM_OFHL_PM = 5'h12, // special block move ops MEM_OSHL_PM = 5'h13, // special block move ops MEM_OSDE_PM = 5'h14, // special block move ops MEM_IOF_C = 5'h15, // special i/o ops MEM_IOS_C = 5'h16, // operand is ar MEM_IOF_N = 5'h17, MEM_IOS_N = 5'h18, MEM_OS_HL_N = 5'h19, MEM_OSSP_PCM2 = 5'h1a, // int code (call //MEM_OSSP_P = 5'h1b, // MEM_INTA = 5'h1c, MEM_IFINT = 5'h1d, MEM_DECPC = 5'h1e ; //-------1---------2---------3--------Wires----------------6---------7---------8---------9--------0 wire cb_mem; wire wb_rdy_nhz; wire dec_blk_inc; wire we_next; wire hazard; wire wb_int; wire [15:0] hl, de, bc; wire [3:0] mem_exec_dec; // don't forget that as 1r1 is executed it is transferred to ir2. Anything I need to know // about subsequent operations must be stored. // 6 5 4 15 // assign {next_dec_state, next_mem_state, next_pipe_state} = next_state; wire [5:0] next_dec_state; wire [4:0] next_mem_state; wire [3:0] next_pipe_state; wire ed_dbl_rd; wire [15:0] hl_or_ixiy; // hharte wire ed_blk_mv; wire ed_blk_in; wire ed_blk_out; wire [15:0] mux21; //-------1---------2---------3--------Registers------------6---------7---------8---------9--------0 reg [15:0] pc; reg [15:0] sp; reg [15:0] wb_adr_o; reg wb_we_o; reg wb_cyc_o; reg wb_stb_o; //reg wb_lock; Not used (yet -- don't delete) reg [1:0] wb_tga_o; reg blk_inc_flg; reg [9:0] ir1, ir2; reg ir1dd, ir2dd; reg ir1fd, ir2fd; reg [15:0] nn; reg [14:0] next_state; // a wire assigned in an alowys loop. reg [5:0] dec_state; // the register set each clock from next_dec_state; //reg of16_reg, os16_reg, rmw8_reg, call_reg, ret_reg, ioi; //reg push_reg; //reg pop_reg; reg inst_haz; reg exec_ir2; reg blk_rpt_flg; reg blk_io_flg; reg flag_os1; reg int_en, en_int_next; reg wb_irq_sync; reg ex_tos_hl; // special flag to help implement EXs6SP7_HL //-------1---------2---------3--------Assignments----------6---------7---------8---------9--------0 // // ir is 10 bits most significant codes ir1[9:8] = { EDgrp, CBgrp } DDgrp and FDgrp are modifiers assign blk_mv_upd_hl = next_mem_state == MEM_OFHL_PM & wb_rdy_nhz| next_mem_state == MEM_OSHL_PM & wb_rdy_nhz ; assign blk_mv_upd_de = next_mem_state == MEM_OSDE_PM & wb_rdy_nhz; // this term not active for compairs as it mucks with flag register in a "blk_mv" way. // we use exec_ir2 to do everything in blk compairs - on the inst_exec file. assign exec_decbc = (dec_state == DEC_ED) & ( ed_blk_mv) & wb_rdy_nhz | (dec_state == DEC_EDBMV3) & wb_rdy_nhz ; assign exec_decb = (dec_state == DEC_ED) & ( ed_blk_in | ed_blk_out) & wb_rdy_nhz| (dec_state == DEC_EDBIN3) & wb_rdy_nhz | (dec_state == DEC_EDBOUT3) & wb_rdy_nhz ; assign wb_dat_o = nn[15:8]; wire sf, zf, f5f, hf, f3f, pvf, nf, cf; assign { sf, zf, f5f, hf, f3f, pvf, nf, cf} = fr; // no load on f5f, f3f ok hf nf used in inst_exec.v assign hl = {hr, lr}; assign de = {dr, er}; assign bc = {br, cr}; assign hl_or_ixiy = ir1dd ? ixr : ir1fd ? iyr : hl ; // this "groups" the instructions to determine first memory operation parameter I1DCNT = 4; // parameter used below simply to make possible change easier. assign mem_exec_dec = {I1DCNT {CBgrp == ir1}} & I1_CB |// CBgrp is rotates and bi {I1DCNT {DDgrp == ir1}} & I1_DDFD|// DDgrp {I1DCNT {FDgrp == ir1}} & I1_DDFD|// FDgrp FD {I1DCNT {EDgrp == ir1}} & I1_ED |// EDgrp ED {I1DCNT {JPsHL == ir1}} & I1_JMP |// JP HL ; E9 // doc {I1DCNT {ADCsA_N == ir1}} & I1_N |// ADC A,N ; CE XX {I1DCNT {ADDsA_N == ir1}} & I1_N |// ADD A,N ; C6 XX {I1DCNT {ANDsN == ir1}} & I1_N |// AND N ; E6 XX {I1DCNT {CPsN == ir1}} & I1_N |// CP N ; FE XX {I1DCNT {INsA_6N7 == ir1}} & I1_N |// IN A,(N) ; DB XX {I1DCNT {JRs$t2 == ir1}} & I1_JMPR|// JR $+2 ; 18 XX {I1DCNT {JRsC_$t2 == ir1}} & I1_JMPR|// JR C,$+2 ; 38 XX {I1DCNT {JRsNC_$t2 == ir1}} & I1_JMPR|// JR NC,$+2 ; 30 XX {I1DCNT {JRsZ_$t2 == ir1}} & I1_JMPR|// JR Z,$+2 ; 28 XX {I1DCNT {JRsNZ_$t2 == ir1}} & I1_JMPR|// JR NZ,$+2 ; 20 XX {I1DCNT {LDs6HL7_N == ir1}} & I1_N |// LD (HL),N ; 36 XX {I1DCNT {LDsA_N == ir1}} & I1_N |// LD A,N ; 3E XX {I1DCNT {LDsB_N == ir1}} & I1_N |// LD B,N ; 06 XX {I1DCNT {LDsC_N == ir1}} & I1_N |// LD C,N ; 0E XX {I1DCNT {LDsD_N == ir1}} & I1_N |// LD D,N ; 16 XX {I1DCNT {LDsE_N == ir1}} & I1_N |// LD E,N ; 1E XX {I1DCNT {LDsH_N == ir1}} & I1_N |// LD H,N ; 26 XX {I1DCNT {LDsL_N == ir1}} & I1_N |// LD L,N ; 2E XX {I1DCNT {ORsN == ir1}} & I1_N |// OR N ; F6 XX {I1DCNT {OUTs6N7_A == ir1}} & I1_N |// OUT (N),A ; D3 XX {I1DCNT {SBCsA_N == ir1}} & I1_N |// SBC A,N ; DE XX {I1DCNT {SUBsN == ir1}} & I1_N |// SUB N ; D6 XX {I1DCNT {XORsN == ir1}} & I1_N |// XOR N ; EE XX {I1DCNT {CALLsC_NN == ir1}} & I1_NN |// CALL C,NN ; DC XX XX {I1DCNT {CALLsNC_NN == ir1}} & I1_NN |// CALL NC,NN ; D4 XX XX {I1DCNT {CALLsNN == ir1}} & I1_NN |// CALL NN ; CD XX XX {I1DCNT {CALLsNZ_NN == ir1}} & I1_NN |// CALL NZ,NN ; C4 XX XX {I1DCNT {CALLsPE_NN == ir1}} & I1_NN |// CALL PE,NN ; EC XX XX {I1DCNT {CALLsPO_NN == ir1}} & I1_NN |// CALL PO,NN ; E4 XX XX {I1DCNT {CALLsP_NN == ir1}} & I1_NN |// CALL P,NN ; F4 XX XX {I1DCNT {CALLsZ_NN == ir1}} & I1_NN |// CALL Z,NN ; CC XX XX {I1DCNT {CALLsM_NN == ir1}} & I1_NN |// CALL M,NN ; FC XX XX {I1DCNT {JP == ir1}} & I1_NN |// JP ; C3 XX XX {I1DCNT {JPsC == ir1}} & I1_NN |// JP C ; DA XX XX {I1DCNT {JPsM == ir1}} & I1_NN |// JP M, ; FA XX XX {I1DCNT {JPsNC == ir1}} & I1_NN |// JP NC, ; D2 XX XX {I1DCNT {JPsNZ == ir1}} & I1_NN |// JP NZ ; C2 XX XX {I1DCNT {JPsP == ir1}} & I1_NN |// JP P ; F2 XX XX {I1DCNT {JPsPE == ir1}} & I1_NN |// JP PE, ; EA XX XX {I1DCNT {JPsPO == ir1}} & I1_NN |// JP PO ; E2 XX XX {I1DCNT {JPsZ == ir1}} & I1_NN |// JP Z ; CA XX XX {I1DCNT {LDs6NN7_A == ir1}} & I1_NN |// LD (NN),A ; 32 XX XX {I1DCNT {LDs6NN7_HL == ir1}} & I1_NN |// LD (NN),HL ; 22 XX XX {I1DCNT {LDsA_6NN7 == ir1}} & I1_NN |// LD A,(NN) ; 3A XX XX {I1DCNT {LDsBC_NN == ir1}} & I1_NN |// LD BC,NN ; 01 XX XX {I1DCNT {LDsDE_NN == ir1}} & I1_NN |// LD DE,NN ; 11 XX XX {I1DCNT {LDsHL_6NN7 == ir1}} & I1_NN |// LD HL,(NN) ; 2A XX XX {I1DCNT {LDsHL_NN == ir1}} & I1_NN |// LD HL,NN ; 21 XX XX {I1DCNT {LDsSP_NN == ir1}} & I1_NN |// LD SP,NN ; 31 XX XX {I1DCNT {ADCsA_6HL7 == ir1}} & I1_OF |// ADC A,(HL) ; 8E {I1DCNT {ADDsA_6HL7 == ir1}} & I1_OF |// ADD A,(HL) ; 86 {I1DCNT {ANDs6HL7 == ir1}} & I1_OF |// AND (HL) ; A6 {I1DCNT {CPs6HL7 == ir1}} & I1_OF |// CP (HL) ; BE {I1DCNT {LDsA_6BC7 == ir1}} & I1_OF |// LD A,(BC) ; 0A {I1DCNT {LDsA_6DE7 == ir1}} & I1_OF |// LD A,(DE) ; 1A {I1DCNT {LDsA_6HL7 == ir1}} & I1_OF |// LD A,(HL) ; 7E {I1DCNT {LDsB_6HL7 == ir1}} & I1_OF |// LD B,(HL) ; 46 {I1DCNT {LDsC_6HL7 == ir1}} & I1_OF |// LD C,(HL) ; 4E {I1DCNT {LDsD_6HL7 == ir1}} & I1_OF |// LD D,(HL) ; 56 {I1DCNT {LDsE_6HL7 == ir1}} & I1_OF |// LD E,(HL) ; 5E {I1DCNT {LDsH_6HL7 == ir1}} & I1_OF |// LD H,(HL) ; 66 {I1DCNT {LDsL_6HL7 == ir1}} & I1_OF |// LD L,(HL) ; 6E {I1DCNT {ORs6HL7 == ir1}} & I1_OF |// OR (HL) ; B6 {I1DCNT {SBCs6HL7 == ir1}} & I1_OF |// SBC (HL) ; 9E {I1DCNT {SUBs6HL7 == ir1}} & I1_OF |// SUB (HL) ; 96 {I1DCNT {XORs6HL7 == ir1}} & I1_OF |// XOR (HL) ; AE {I1DCNT {LDs6BC7_A == ir1}} & I1_OS |// LD (BC),A ; 02 {I1DCNT {LDs6DE7_A == ir1}} & I1_OS |// LD (DE),A ; 12 {I1DCNT {LDs6HL7_A == ir1}} & I1_OS |// LD (HL),A ; 77 {I1DCNT {LDs6HL7_B == ir1}} & I1_OS |// LD (HL),B ; 70 {I1DCNT {LDs6HL7_C == ir1}} & I1_OS |// LD (HL),C ; 71 {I1DCNT {LDs6HL7_D == ir1}} & I1_OS |// LD (HL),D ; 72 {I1DCNT {LDs6HL7_E == ir1}} & I1_OS |// LD (HL),E ; 73 {I1DCNT {LDs6HL7_H == ir1}} & I1_OS |// LD (HL),H ; 74 {I1DCNT {LDs6HL7_L == ir1}} & I1_OS |// LD (HL),L ; 75 {I1DCNT {POPsAF == ir1}} & I1_POP |// POP AF ; F1 {I1DCNT {POPsBC == ir1}} & I1_POP |// POP BC ; C1 {I1DCNT {POPsDE == ir1}} & I1_POP |// POP DE ; D1 {I1DCNT {POPsHL == ir1}} & I1_POP |// POP HL ; E1 {I1DCNT {PUSHsAF == ir1}} & I1_PUSH|// PUSH AF ; F5 {I1DCNT {PUSHsBC == ir1}} & I1_PUSH|// PUSH BC ; C5 {I1DCNT {PUSHsDE == ir1}} & I1_PUSH|// PUSH DE ; D5 {I1DCNT {PUSHsHL == ir1}} & I1_PUSH|// PUSH HL ; E5 {I1DCNT {ADCsA_A == ir1}} & I1_R2R |// ADC A,A ; 8F {I1DCNT {ADCsA_B == ir1}} & I1_R2R |// ADC A,B ; 88 {I1DCNT {ADCsA_C == ir1}} & I1_R2R |// ADC A,C ; 89 {I1DCNT {ADCsA_D == ir1}} & I1_R2R |// ADC A,D ; 8A {I1DCNT {ADCsA_E == ir1}} & I1_R2R |// ADC A,E ; 8B {I1DCNT {ADCsA_H == ir1}} & I1_R2R |// ADC A,H ; 8C {I1DCNT {ADCsA_L == ir1}} & I1_R2R |// ADC A,L ; 8D {I1DCNT {ADDsA_A == ir1}} & I1_R2R |// ADD A,A ; 87 {I1DCNT {ADDsA_B == ir1}} & I1_R2R |// ADD A,B ; 80 {I1DCNT {ADDsA_C == ir1}} & I1_R2R |// ADD A,C ; 81 {I1DCNT {ADDsA_D == ir1}} & I1_R2R |// ADD A,D ; 82 {I1DCNT {ADDsA_E == ir1}} & I1_R2R |// ADD A,E ; 83 {I1DCNT {ADDsA_H == ir1}} & I1_R2R |// ADD A,H ; 84 {I1DCNT {ADDsA_L == ir1}} & I1_R2R |// ADD A,L ; 85 {I1DCNT {ADDsHL_BC == ir1}} & I1_R2R |// ADD HL,BC ; 09 {I1DCNT {ADDsHL_DE == ir1}} & I1_R2R |// ADD HL,DE ; 19 {I1DCNT {ADDsHL_HL == ir1}} & I1_R2R |// ADD HL,HL ; 29 {I1DCNT {ADDsHL_SP == ir1}} & I1_R2R |// ADD HL,SP ; 39 {I1DCNT {ANDsA == ir1}} & I1_R2R |// AND A ; A7 {I1DCNT {ANDsB == ir1}} & I1_R2R |// AND B ; A0 {I1DCNT {ANDsC == ir1}} & I1_R2R |// AND C ; A1 {I1DCNT {ANDsD == ir1}} & I1_R2R |// AND D ; A2 {I1DCNT {ANDsE == ir1}} & I1_R2R |// AND E ; A3 {I1DCNT {ANDsH == ir1}} & I1_R2R |// AND H ; A4 {I1DCNT {ANDsL == ir1}} & I1_R2R |// AND L ; A5 {I1DCNT {CCF == ir1}} & I1_R2R |// CCF ; 3F {I1DCNT {CPL == ir1}} & I1_R2R |// CPL ; 2F {I1DCNT {CPsA == ir1}} & I1_R2R |// CP A ; BF {I1DCNT {CPsB == ir1}} & I1_R2R |// CP B ; B8 {I1DCNT {CPsC == ir1}} & I1_R2R |// CP C ; B9 {I1DCNT {CPsD == ir1}} & I1_R2R |// CP D ; BA {I1DCNT {CPsE == ir1}} & I1_R2R |// CP E ; BB {I1DCNT {CPsH == ir1}} & I1_R2R |// CP H ; BC {I1DCNT {CPsL == ir1}} & I1_R2R |// CP L ; BD {I1DCNT {DAA == ir1}} & I1_R2R |// DAA ; 27 {I1DCNT {DECsA == ir1}} & I1_R2R |// DEC A ; 3D {I1DCNT {DECsB == ir1}} & I1_R2R |// DEC B ; 05 {I1DCNT {DECsBC == ir1}} & I1_R2R |// DEC BC ; 0B {I1DCNT {DECsC == ir1}} & I1_R2R |// DEC C ; 0D {I1DCNT {DECsD == ir1}} & I1_R2R |// DEC D ; 15 {I1DCNT {DECsDE == ir1}} & I1_R2R |// DEC DE ; 1B {I1DCNT {DECsE == ir1}} & I1_R2R |// DEC E ; 1D {I1DCNT {DECsH == ir1}} & I1_R2R |// DEC H ; 25 {I1DCNT {DECsHL == ir1}} & I1_R2R |// DEC HL ; 2B {I1DCNT {DECsL == ir1}} & I1_R2R |// DEC L ; 2D {I1DCNT {DECsSP == ir1}} & I1_R2R |// DEC SP ; 3B {I1DCNT {DI == ir1}} & I1_R2R |// DI ; F3 {I1DCNT {DJNZs$t2 == ir1}} & I1_JMPR|// DJNZ $+2 ; 10 XX {I1DCNT {EI == ir1}} & I1_R2R |// EI ; FB {I1DCNT {EXX == ir1}} & I1_R2R |// EXX ; D9 {I1DCNT {EXsAF_AFp == ir1}} & I1_R2R |// EX AF,AF' ; 08 {I1DCNT {EXsDE_HL == ir1}} & I1_R2R |// EX DE,HL ; EB {I1DCNT {HALT == ir1}} & I1_HALT |// HALT ; 76 {I1DCNT {INCsA == ir1}} & I1_R2R |// INC A ; 3C {I1DCNT {INCsB == ir1}} & I1_R2R |// INC B ; 04 {I1DCNT {INCsBC == ir1}} & I1_R2R |// INC BC ; 03 {I1DCNT {INCsC == ir1}} & I1_R2R |// INC C ; 0C {I1DCNT {INCsD == ir1}} & I1_R2R |// INC D ; 14 {I1DCNT {INCsDE == ir1}} & I1_R2R |// INC DE ; 13 {I1DCNT {INCsE == ir1}} & I1_R2R |// INC E ; 1C {I1DCNT {INCsH == ir1}} & I1_R2R |// INC H ; 24 {I1DCNT {INCsHL == ir1}} & I1_R2R |// INC HL ; 23 {I1DCNT {INCsL == ir1}} & I1_R2R |// INC L ; 2C {I1DCNT {INCsSP == ir1}} & I1_R2R |// INC SP ; 33 {I1DCNT {LDsA_A == ir1}} & I1_R2R |// LD A,A ; 7F {I1DCNT {LDsA_B == ir1}} & I1_R2R |// LD A,B ; 78 {I1DCNT {LDsA_C == ir1}} & I1_R2R |// LD A,C ; 79 {I1DCNT {LDsA_D == ir1}} & I1_R2R |// LD A,D ; 7A {I1DCNT {LDsA_E == ir1}} & I1_R2R |// LD A,E ; 7B {I1DCNT {LDsA_H == ir1}} & I1_R2R |// LD A,H ; 7C {I1DCNT {LDsA_L == ir1}} & I1_R2R |// LD A,L ; 7D {I1DCNT {LDsB_A == ir1}} & I1_R2R |// LD B,A ; 47 {I1DCNT {LDsB_B == ir1}} & I1_R2R |// LD B,B ; 40 {I1DCNT {LDsB_C == ir1}} & I1_R2R |// LD B,C ; 41 {I1DCNT {LDsB_D == ir1}} & I1_R2R |// LD B,D ; 42 {I1DCNT {LDsB_E == ir1}} & I1_R2R |// LD B,E ; 43 {I1DCNT {LDsB_H == ir1}} & I1_R2R |// LD B,H ; 44 {I1DCNT {LDsB_L == ir1}} & I1_R2R |// LD B,L ; 45 {I1DCNT {LDsC_A == ir1}} & I1_R2R |// LD C,A ; 4F {I1DCNT {LDsC_B == ir1}} & I1_R2R |// LD C,B ; 48 {I1DCNT {LDsC_C == ir1}} & I1_R2R |// LD C,C ; 49 {I1DCNT {LDsC_D == ir1}} & I1_R2R |// LD C,D ; 4A {I1DCNT {LDsC_E == ir1}} & I1_R2R |// LD C,E ; 4B {I1DCNT {LDsC_H == ir1}} & I1_R2R |// LD C,H ; 4C {I1DCNT {LDsC_L == ir1}} & I1_R2R |// LD C,L ; 4D {I1DCNT {LDsD_A == ir1}} & I1_R2R |// LD D,A ; 57 {I1DCNT {LDsD_B == ir1}} & I1_R2R |// LD D,B ; 50 {I1DCNT {LDsD_C == ir1}} & I1_R2R |// LD D,C ; 51 {I1DCNT {LDsD_D == ir1}} & I1_R2R |// LD D,D ; 52 {I1DCNT {LDsD_E == ir1}} & I1_R2R |// LD D,E ; 53 {I1DCNT {LDsD_H == ir1}} & I1_R2R |// LD D,H ; 54 {I1DCNT {LDsD_L == ir1}} & I1_R2R |// LD D,L ; 55 {I1DCNT {LDsE_A == ir1}} & I1_R2R |// LD E,A ; 5F {I1DCNT {LDsE_B == ir1}} & I1_R2R |// LD E,B ; 58 {I1DCNT {LDsE_C == ir1}} & I1_R2R |// LD E,C ; 59 {I1DCNT {LDsE_D == ir1}} & I1_R2R |// LD E,D ; 5A {I1DCNT {LDsE_E == ir1}} & I1_R2R |// LD E,E ; 5B {I1DCNT {LDsE_H == ir1}} & I1_R2R |// LD E,H ; 5C {I1DCNT {LDsE_L == ir1}} & I1_R2R |// LD E,L ; 5D {I1DCNT {LDsH_A == ir1}} & I1_R2R |// LD H,A ; 67 {I1DCNT {LDsH_B == ir1}} & I1_R2R |// LD H,B ; 60 {I1DCNT {LDsH_C == ir1}} & I1_R2R |// LD H,C ; 61 {I1DCNT {LDsH_D == ir1}} & I1_R2R |// LD H,D ; 62 {I1DCNT {LDsH_E == ir1}} & I1_R2R |// LD H,E ; 63 {I1DCNT {LDsH_H == ir1}} & I1_R2R |// LD H,H ; 64 {I1DCNT {LDsH_L == ir1}} & I1_R2R |// LD H,L ; 65 {I1DCNT {LDsL_A == ir1}} & I1_R2R |// LD L,A ; 6F {I1DCNT {LDsL_B == ir1}} & I1_R2R |// LD L,B ; 68 {I1DCNT {LDsL_C == ir1}} & I1_R2R |// LD L,C ; 69 {I1DCNT {LDsL_D == ir1}} & I1_R2R |// LD L,D ; 6A {I1DCNT {LDsL_E == ir1}} & I1_R2R |// LD L,E ; 6B {I1DCNT {LDsL_H == ir1}} & I1_R2R |// LD L,H ; 6C {I1DCNT {LDsL_L == ir1}} & I1_R2R |// LD L,L ; 6D {I1DCNT {LDsSP_HL == ir1}} & I1_R2R |// LD SP,HL ; F9 {I1DCNT {NOP == ir1}} & I1_R2R |// NOP ; 00 {I1DCNT {ORsA == ir1}} & I1_R2R |// OR A ; B7 {I1DCNT {ORsB == ir1}} & I1_R2R |// OR B ; B0 {I1DCNT {ORsC == ir1}} & I1_R2R |// OR C ; B1 {I1DCNT {ORsD == ir1}} & I1_R2R |// OR D ; B2 {I1DCNT {ORsE == ir1}} & I1_R2R |// OR E ; B3 {I1DCNT {ORsH == ir1}} & I1_R2R |// OR H ; B4 {I1DCNT {ORsL == ir1}} & I1_R2R |// OR L ; B5 {I1DCNT {RLA == ir1}} & I1_R2R |// RLA ; 17 {I1DCNT {RLCA == ir1}} & I1_R2R |// RLCA ; 07 {I1DCNT {RRA == ir1}} & I1_R2R |// RRA ; 1F {I1DCNT {RRCA == ir1}} & I1_R2R |// RRCA ; 0F {I1DCNT {SBCsA == ir1}} & I1_R2R |// SBC A ; 9F {I1DCNT {SBCsB == ir1}} & I1_R2R |// SBC B ; 98 {I1DCNT {SBCsC == ir1}} & I1_R2R |// SBC C ; 99 {I1DCNT {SBCsD == ir1}} & I1_R2R |// SBC D ; 9A {I1DCNT {SBCsE == ir1}} & I1_R2R |// SBC E ; 9B {I1DCNT {SBCsH == ir1}} & I1_R2R |// SBC H ; 9C {I1DCNT {SBCsL == ir1}} & I1_R2R |// SBC L ; 9D {I1DCNT {SCF == ir1}} & I1_R2R |// SCF ; 37 {I1DCNT {SUBsA == ir1}} & I1_R2R |// SUB A ; 97 {I1DCNT {SUBsB == ir1}} & I1_R2R |// SUB B ; 90 {I1DCNT {SUBsC == ir1}} & I1_R2R |// SUB C ; 91 {I1DCNT {SUBsD == ir1}} & I1_R2R |// SUB D ; 92 {I1DCNT {SUBsE == ir1}} & I1_R2R |// SUB E ; 93 {I1DCNT {SUBsH == ir1}} & I1_R2R |// SUB H ; 94 {I1DCNT {SUBsL == ir1}} & I1_R2R |// SUB L ; 95 {I1DCNT {XORsA == ir1}} & I1_R2R |// XOR A ; AF {I1DCNT {XORsB == ir1}} & I1_R2R |// XOR B ; A8 {I1DCNT {XORsC == ir1}} & I1_R2R |// XOR C ; A9 {I1DCNT {XORsD == ir1}} & I1_R2R |// XOR D ; AA {I1DCNT {XORsE == ir1}} & I1_R2R |// XOR E ; AB {I1DCNT {XORsH == ir1}} & I1_R2R |// XOR H ; AC {I1DCNT {XORsL == ir1}} & I1_R2R |// XOR L ; AD {I1DCNT {RET == ir1}} & I1_RET |// RET ; C9 {I1DCNT {RETsC == ir1 & cf }} & I1_RET |// RET C ; D8 {I1DCNT {RETsM == ir1 & sf }} & I1_RET |// RET M ; F8 {I1DCNT {RETsNC== ir1 & ~cf }} & I1_RET |// RET NC ; D0 {I1DCNT {RETsP == ir1 & ~sf }} & I1_RET |// RET P ; F0 {I1DCNT {RETsPE== ir1 & pvf }} & I1_RET |// RET PE ; E8 {I1DCNT {RETsPO== ir1 & ~pvf}} & I1_RET |// RET PO ; E0 {I1DCNT {RETsNZ== ir1 & ~zf }} & I1_RET |// RET NZ ; C0 {I1DCNT {RETsZ == ir1 & zf }} & I1_RET |// RET Z ; C8 {I1DCNT {RETsC == ir1 & ~cf }} & I1_R2R |// RET C ; D8 r2r should work as all codes {I1DCNT {RETsM == ir1 & ~sf }} & I1_R2R |// RET M ; F8 should be nop in ir2 {I1DCNT {RETsNC== ir1 & cf }} & I1_R2R |// RET NC ; D0 {I1DCNT {RETsP == ir1 & sf }} & I1_R2R |// RET P ; F0 {I1DCNT {RETsPE== ir1 & ~pvf}} & I1_R2R |// RET PE ; E8 {I1DCNT {RETsPO== ir1 & pvf }} & I1_R2R |// RET PO ; E0 {I1DCNT {RETsNZ== ir1 & zf }} & I1_R2R |// RET NZ ; C0 {I1DCNT {RETsZ == ir1 & ~zf }} & I1_R2R |// RET Z ; C8 {I1DCNT {EXs6SP7_HL == ir1}} & I1_POP |// EX (SP),HL ; E3 {I1DCNT {DECs6HL7 == ir1}} & I1_RMW |// DEC (HL) ; 35 {I1DCNT {INCs6HL7 == ir1}} & I1_RMW |// INC (HL) ; 34 {I1DCNT {RSTs0 == ir1}} & I1_RST |// RST 0 ; C7 {I1DCNT {RSTs10H == ir1}} & I1_RST |// RST 10H ; D7 {I1DCNT {RSTs18H == ir1}} & I1_RST |// RST 18H ; DF {I1DCNT {RSTs20H == ir1}} & I1_RST |// RST 20H ; E7 {I1DCNT {RSTs28H == ir1}} & I1_RST |// RST 28H ; EF {I1DCNT {RSTs30H == ir1}} & I1_RST |// RST 30H ; F7 {I1DCNT {RSTs38H == ir1}} & I1_RST |// RST 38H ; FF {I1DCNT {RSTs8H == ir1}} & I1_RST ;// RST 8H ; CF //-------- CB decodes ----------------------- // First cut below // CB_RLC = 7'b01_00_000, // these must be compaired with ir[9:3] // CB_RRC = 7'b01_00_001, // these must be compaired with ir[9:3] // CB_RL = 7'b01_00_010, // these must be compaired with ir[9:3] // CB_RR = 7'b01_00_011, // these must be compaired with ir[9:3] // CB_SLA = 7'b01_00_100, // these must be compaired with ir[9:3] // CB_SRA = 7'b01_00_101, // these must be compaired with ir[9:3] // CB_SLL = 7'b01_00_110, // these must be compaired with ir[9:3] // CB_SRL = 7'b01_00_111, // these must be compaired with ir[9:3] // CB_BIT = 4'b01_01, // these must be compaired with ir[9:6] // CB_RES = 4'b01_10, // these must be compaired with ir[9:6] // CB_SET = 4'b01_11, // these must be compaired with ir[9:6] // note these are all read-modify-writ except CB_BIT assign cb_mem = (CB_MEM == ir1[2:0]); // this must be compaired with ir[2:0] // The ED Group // These are the "unique instructions in the 46, 47 rows that NEED? to be implemented // Not sure I want to worry about all undocumented stuff in these rows - hard to believe // It will matter.(IM modes are very system dependent - hard to believe even a programmer // would use undocumented instructions to muck with this stuff) // reg 2 reg simply executed by ir2 logic // ED_IMs0 = 10'h246// IM 0 ; ED 46 set IM0 // ED_LDsI_A = 10'h247// LD I,A ; ED 47 move a to I // ED_IMs1 = 10'h256// IM 1 ; ED 56 set IM1 // ED_LDsA_I = 10'h257// LD A,I ; ED 57 move I to A // ED_IMs2 = 10'h25E// IM 2 ; ED 5E set IM2 // ED_RRD = 10'h267// RRD ; ED 67 nibble roates A HL // ED_RLD = 10'h26F// RLD ; ED 6F nibble roates A HL // set (or clear) repeat flag at DEC_EB. // set (or clear) inc flag at DEC_EB. // seperate flows for LD, CP, IN, OUT. // ED_LDI == ir1// LDI ; ED A0 These are block move // ED_CPI == ir1// CPI ; ED A1 type insts that don't repeat // ED_INI == ir1// INI ; ED A2 // ED_OUTI == ir1// OUTI ; ED A3 // ED_LDD == ir1// LDD ; ED A8 // ED_CPD == ir1// CPD ; ED A9 // ED_IND == ir1// IND ; ED AA // ED_OUTD == ir1// OUTD ; ED AB wire dec_blk_rpt = ED_LDIR == ir1 |// LDIR ; ED B0 These are block move ED_CPIR == ir1 |// CPIR ; ED B1 type insts that DO repeat ED_INIR == ir1 |// INIR ; ED B2 ED_OTIR == ir1 |// OTIR ; ED B3 ED_LDDR == ir1 |// LDDR ; ED B8 ED_CPDR == ir1 |// CPDR ; ED B9 ED_INDR == ir1 |// INDR ; ED BA ED_OTDR == ir1 ;// OTDR ; ED BB // hharte assign ed_blk_mv = ED_LDIR == ir1 | ED_LDI == ir1 | ED_LDDR == ir1 | ED_LDD == ir1 ; wire ed_blk_cp = ED_CPIR == ir1 | ED_CPI == ir1 | ED_CPDR == ir1 | ED_CPD == ir1 ; assign ed_blk_in = ED_INIR == ir1 | ED_INI == ir1 | ED_INDR == ir1 | ED_IND == ir1 ; assign ed_blk_out = ED_OTIR == ir1 | ED_OUTI == ir1 | ED_OTDR == ir1 | ED_OUTD == ir1 ; wire dec_blk_io = ed_blk_in | ed_blk_out; wire blk_done = ~blk_rpt_flg | beq0 & ceq0 | blk_io_flg & beq0; wire blk_cpi_done = ~blk_rpt_flg | ({br, cr} == 16'h1); assign dec_blk_inc = ED_LDIR == ir1 | ED_CPIR == ir1 | ED_INIR == ir1 | ED_OTIR == ir1 | ED_LDI == ir1 | ED_CPI == ir1 | ED_INI == ir1 | ED_OUTI == ir1 ; //The ED70 instruction reads from I/O port C, //but does not store the result. //It just affects the flags. Hard to test. like the other IN x,(C) instruction. // //ED71 simply outs the value 0 to I/O port C. // This suggests that we should decode as follows: // I hope if I don't get all the IM duplicates right it won't be a tragedy // // ED_INsREG_6C7 = 7'b1001___000, // compair with {ir[9:6],ir[2:0]} // ED_OUTs6C7_REG = 7'b1001___001, // compair with {ir[9:6],ir[2:0]} // ED_SBCsHL_REG = 8'b1001__0010, // compair with {ir[9:6],ir[3:0]} // ED_ADCsHL_REG = 8'b1001__1010, // compair with {ir[9:6],ir[3:0]} // ED_LDs6NN7_REG = 8'b1001__0011, // compair with {ir[9:6],ir[3:0]} REG = BC,DE,HL,SP // ED_LDsREG_6NN7 = 8'b1001__1011, // compair with {ir[9:6],ir[3:0]} REG = BC,DE,HL,SP // ED_NEG = 7'b1001___100, // compair with {ir[9:6],ir[2:0]} all A<= -A // ED_RETN = 7'b1001___101, // compair with {ir[9:6],ir[2:0]} and !reti wire ed_in_reg = ED_INsREG_6C7 == {ir1[9:6],ir1[2:0]}; wire ed_out_reg = ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]}; wire ed_nn = ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} | ED_LDsREG_6NN7 == {ir1[9:6],ir1[3:0]} ; // we use all these to enable interrupts wire ed_retn = ED_RETN == {ir1[9:6],ir1[2:0]}; wire ed_rmw = ED_RRD == ir1 | // ED 67 nibble roates A (HL) ED_RLD == ir1 ; // ED 6F nibble roates A (HL) assign ed_dbl_rd = ED_LDsREG_6NN7 == {ir1[9:6],ir1[3:0]}; // assign cb_mem = CB_MEM = ir1[2:0]; // CB_MEM = 3'h110, wire jmpr_true = JRs$t2 == ir1 | JRsC_$t2 == ir1 & fr[0] | JRsNC_$t2 == ir1 & ~fr[0] | JRsZ_$t2 == ir1 & fr[6] | JRsNZ_$t2 == ir1 & ~fr[6] | DJNZs$t2 == ir1 & (br != 8'h1); wire jmpr = JRs$t2 == ir1 | JRsC_$t2 == ir1 | JRsNC_$t2 == ir1 | JRsZ_$t2 == ir1 | JRsNZ_$t2 == ir1 | DJNZs$t2 == ir1; //assign { sf, zf. f5f, hf, f3f, pvf, nf, cf} = fr; wire callnn_true = CALLsC_NN == ir1 & cf | CALLsNC_NN == ir1 & ~cf | CALLsNN == ir1 | CALLsNZ_NN == ir1 & ~zf | CALLsPE_NN == ir1 & pvf | CALLsPO_NN == ir1 & ~pvf| CALLsP_NN == ir1 & ~sf | CALLsZ_NN == ir1 & zf | CALLsM_NN == ir1 & sf ; wire jmpnn_true = JPsC == ir1 & cf | JPsNC == ir1 & ~cf | JP == ir1 | JPsNZ == ir1 & ~zf | JPsPE == ir1 & pvf | JPsPO == ir1 & ~pvf| JPsP == ir1 & ~sf | JPsZ == ir1 & zf | JPsM == ir1 & sf ; // PUSHsAF == ir1 // PUSHsBC == ir1 // PUSHsDE == ir1 // PUSHsHL == ir1 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 == {ir1[9:6],ir1[2:0]}) & REG8_A == ir1[5:3] ; wire os_b = LDs6HL7_B == ir1 | // LD (HL),B ; 70 ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_BC == ir1[5:4] | PUSHsBC == ir1 | // PUSH BC ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_B == ir1[5:3] ; wire os_c = LDs6HL7_C == ir1 | // LD (HL),C ; 71 ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_C == ir1[5:3] ; wire os_d = LDs6HL7_D == ir1 | // LD (HL),D ; 72 PUSHsDE == ir1 | // PUSH DE ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_DE == ir1[5:4] | ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_D == ir1[5:3] ; wire os_e = LDs6HL7_E == ir1 | // LD (HL),E ; 73 ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_E == ir1[5:3] ; wire os_h = LDs6HL7_H == ir1 | // LD (HL),H ; 74 PUSHsHL == ir1 | // need this here for hazard detect ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_H == ir1[5:3] ; wire os_l = LDs6HL7_L == ir1 | // LD (HL),L ; 75 ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_L == ir1[5:3] ; // these need special treatment of nn register, but as each is an NN type, there // is no risk of a hazard. wire os_bc = ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_BC == ir1[5:4]; wire os_de = ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_DE == ir1[5:4]; wire os_sp = ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_SP == ir1[5:4]; wire os_hl = LDs6NN7_HL == ir1 & ~(ir1dd | ir2dd) | ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_HL == ir1[5:4] ; wire os_ixr = LDs6NN7_HL == ir1 & ir1dd; wire os_iyr = LDs6NN7_HL == ir1 & ir1fd; // wire os_sp = ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_SP == ir1[5:4]; not used ? // wire os_f = PUSHsAF == ir1 ; //---------------- inst hazard ---------------------------------------------------------- // // On some reflection, I don't think I'm going to worry about this immediately - it // should be easy to kludge in a fix if necessary -- and there are more important things // todo. It is a very bad programming practice to muck with the instruction stream in any // case -- I have to believe most target applications do not do this -- although I'll probably // get hit pretty early with a instruction test that does. Oh well -- if that happens we fix // it. // Well -- think some here -- the hazard is because of a change in design. // If used to any extent.. Somebody WILL // want this to act the same way as the origional - even if the programming is "poor". // >>>>>>>> bite the bullet and do it. // // if we do an operand store and the address == pc-1 its an inst hazard, We need to execute the // store decrement pc and re-fetch. This is a high priority interrupt. // what about multi-byte stores - like LDs6NN7_A or LDs6NN7_HL - i guess we do an IF - to start // the pipe before the os -- same logic. // //-----------------data hazard ---------------------------------------------------------- // // Issues here have evolved to a degree as the design progressed. However the // Key has always been that for each instruction (no matter how complex) there // is only a single state in which the previous instruction can also be active // and that is the DEC_EXEC state. If there is a data hazard, we need to delay // execution of that state until the ir2 execution completes (which it always does // in a single tick). Note that only the RET instructions test the flag register // on DEC_EXEC. // // WARNING: be very careful about this. Data hazard logic is very difficult to // verify as there are so many instruction pairs to test. // // Situations 1) operand stores from ir1 when register is updated in ir2 // 2) flag tests when fr is being updated // 3) sp issues see below LDsSP_HL DECsSP INCsSP // ANY OTHERS ??? // 4) Indirect addressing -(HL) (BC) (DE) when address registers are updated // // upd_ar, upd_br, upd_cr, upd_dr, upd_er, upd_hr, upd_lr,upd_fr, wire use_hl_exec = LDsSP_HL == ir1 | INCs6HL7 == ir1 | ADCsA_6HL7 == ir1 | SBCs6HL7 == ir1 | ADDsA_6HL7 == ir1 | SUBs6HL7 == ir1 | ANDs6HL7 == ir1 | XORs6HL7 == ir1 | CPs6HL7 == ir1 | LDs6HL7_A == ir1 | LDsA_6HL7 == ir1 | LDs6HL7_B == ir1 | LDsB_6HL7 == ir1 | LDs6HL7_C == ir1 | LDsC_6HL7 == ir1 | LDs6HL7_D == ir1 | LDsD_6HL7 == ir1 | LDs6HL7_E == ir1 | LDsE_6HL7 == ir1 | LDs6HL7_H == ir1 | LDsH_6HL7 == ir1 | LDs6HL7_L == ir1 | LDsL_6HL7 == ir1 | JPsHL == ir1 | ORs6HL7 == ir1 | DECs6HL7 == ir1 | PUSHsHL == ir1; wire use_bc_exec = LDsA_6BC7 == ir1 | LDs6BC7_A == ir1 | PUSHsBC == ir1 ; wire use_de_exec = LDs6DE7_A == ir1 | LDsA_6DE7 == ir1 | PUSHsDE == ir1 ; wire use_sp_exec = MEM_OFSP == next_mem_state | MEM_OSSP == next_mem_state ; wire upd_sp_exec = DECsSP == ir2 | INCsSP == ir2 ; wire use_fr_exec = ( RETsC == ir1 | RETsM == ir1 | RETsNC == ir1 | RETsP == ir1 | RETsPE == ir1 | RETsPO == ir1 | RETsNZ == ir1 | RETsZ == ir1 | PUSHsAF == ir1 ) ; assign hazard = (dec_state == DEC_EXEC & exec_ir2 ) & ( upd_fr & use_fr_exec | upd_ar & os_a | upd_br & os_b | upd_br & use_bc_exec | upd_cr & os_c | upd_cr & use_bc_exec | upd_dr & os_d | upd_dr & use_de_exec | upd_er & os_e | upd_er & use_de_exec | upd_hr & os_h | upd_lr & os_l | upd_hr & use_hl_exec | upd_lr & use_hl_exec | upd_sp_exec & use_sp_exec ); //----------------- inst hazard logic ------------------------------------------ always @(posedge wb_clk_i or posedge rst_i) if (rst_i) inst_haz <= 1'b0; else if (we_next & (pc - 16'h1) == mux21) inst_haz <= 1'b1; else if (dec_state == DEC_EXEC) inst_haz <= 1'b0; // highest priority interrupt // 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; // old logic not used //assign use_flags = c_jmp8 | c_jmp4 | c_call | c_ret; //wire bc_eq0 = beq0 & ceq0; // ??? not used ? why defined ? I simply re-wrote the test re-name //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 | // |_____| | |/ | | | | // ------------------->| | | | // |_____| |_____| // MEM_NOP // MEM_IFPP1 MEM_OFIXpD MEM_CALL MEM_RST MEM_OFHL_PM MEM_IOF_C // MEM_OS1, MEM_OSIXpD MEM_OSNN, MEM_REL2PC MEM_OSHL_PM MEM_IOS_C // MEM_OF1, MEM_OSADR MEM_OFNN MEM_JMPHL MEM_OSDE_PM MEM_IOF_N // MEM_OFSP MEM_OSSP_PCM2 MEM_OFADRP1 MEM_IFNN MEM_INTA MEM_IOS_N // MEM_OSSP MEM_OSSP_P MEM_OSADRP1 MEM_IFINT MEM_OS_HL_N // wire src_sp = next_mem_state == MEM_OFSP | next_mem_state == MEM_OSSP | next_mem_state == MEM_OSSP_PCM2 | next_mem_state == MEM_CALL ; wire src_pc = next_mem_state == MEM_IFPP1 | next_mem_state == MEM_REL2PC ; wire src_nn = next_mem_state == MEM_IFNN | next_mem_state == MEM_OSNN | next_mem_state == MEM_OFNN ; wire src_de = dec_state == DEC_EXEC & LDsA_6DE7 == ir1 | // MEM_OS1 MEM_OF1 dec_state == DEC_EXEC & LDs6DE7_A == ir1 | // are both true at this time next_mem_state == MEM_OSDE_PM ; wire src_bc = dec_state == DEC_EXEC & LDsA_6BC7 == ir1 | dec_state == DEC_EXEC & LDs6BC7_A == ir1 | next_mem_state ==MEM_IOF_C | next_mem_state ==MEM_IOS_C ; // don't forget that hl source can be modified by prefix // this gets messy as we use wb_adr_o for some of these. // wire src_hl = next_mem_state == MEM_OF1 & !src_de & !src_bc & !src_sp | next_mem_state == MEM_OS1 & !src_de & !src_bc | next_mem_state == MEM_OFHL_PM | next_mem_state == MEM_OSHL_PM | next_mem_state == MEM_OS_HL_N | next_mem_state == MEM_JMPHL & !( ir1dd | ir1fd); wire src_ix = next_mem_state == MEM_OFIXpD & ir1dd | next_mem_state == MEM_JMPHL & ir1dd | next_mem_state == MEM_OSIXpD & ir1dd ; wire src_iy = next_mem_state == MEM_OFIXpD & ir1fd | next_mem_state == MEM_JMPHL & ir1fd | next_mem_state == MEM_OSIXpD & ir1fd ; wire src_adr = next_mem_state == MEM_OFADRP1 | next_mem_state == MEM_OSADRP1 | next_mem_state == MEM_NOP | next_mem_state == MEM_OSADR ; wire src_io = next_mem_state == MEM_IOF_N | next_mem_state == MEM_IOS_N ; wire src_int = next_mem_state == MEM_IFINT ; wire [15:0] 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 | {16{ src_ix }} & ixr | {16{ src_iy }} & iyr | {16{ src_adr }} & wb_adr_o | {16{ src_int }} & {intr, nn[15:8] } | {16{ src_io }} & { br, nn[15:8] } ; wire block_mv_inc = (dec_state == DEC_ED) ? dec_blk_inc : blk_inc_flg; // flag set at DEC_ED wire inc = next_mem_state ==MEM_OFADRP1 | next_mem_state ==MEM_OSADRP1 | next_mem_state ==MEM_OFHL_PM & block_mv_inc | next_mem_state ==MEM_OSHL_PM & block_mv_inc | next_mem_state ==MEM_OSDE_PM & block_mv_inc | next_mem_state ==MEM_OFSP | next_mem_state ==MEM_IFPP1 | next_mem_state ==MEM_JMPHL | next_mem_state ==MEM_IFINT | next_mem_state ==MEM_IFNN | next_mem_state ==MEM_OFNN | next_mem_state ==MEM_OSNN | next_mem_state ==MEM_RST ; //next_mem_state ==MEM_OSSP_P ; wire dec = next_mem_state ==MEM_OFHL_PM & ~block_mv_inc | next_mem_state ==MEM_OSHL_PM & ~block_mv_inc | next_mem_state ==MEM_OSDE_PM & ~block_mv_inc | next_mem_state ==MEM_OSSP_PCM2 | next_mem_state ==MEM_CALL | next_mem_state == MEM_OSSP ; wire reln = next_mem_state == MEM_REL2PC | next_mem_state == MEM_OFIXpD | next_mem_state == MEM_OSIXpD ; wire [15:0] src2 = {16{ inc }} & 16'h0001 | {16{ dec }} & 16'hffff | {16{ reln }} & {{8{nn[15]}},nn[15:8]}| {16{~(reln | inc | dec)}} & 16'h0 ;// lint complains that this signal // has no load -YES it is not needed - // more for information -- amazing complaint though wire [15:0] adr_alu = src2 + src_mux; wire pre_inc_dec = next_mem_state == MEM_CALL | //next_mem_state == MEM_OSSP_P | next_mem_state == MEM_REL2PC | next_mem_state == MEM_OFIXpD | next_mem_state == MEM_OSIXpD | next_mem_state == MEM_OFADRP1 | next_mem_state == MEM_OSADRP1 | next_mem_state == MEM_OSSP_PCM2 | next_mem_state == MEM_OSSP ; assign mux21 = pre_inc_dec ? adr_alu : src_mux; assign wb_rdy_nhz = (!wb_cyc_o | wb_ack_i ) & ~hazard; // wishbone ready with no hazard wire wb_rdy = !wb_cyc_o | wb_ack_i; assign we_next = next_mem_state == MEM_OS1 | next_mem_state == MEM_OSSP | next_mem_state == MEM_OSIXpD | next_mem_state == MEM_OSADR | next_mem_state == MEM_OSSP_PCM2 | //next_mem_state == MEM_OSSP_P | next_mem_state == MEM_CALL | next_mem_state == MEM_OSNN | next_mem_state == MEM_OSADRP1 | next_mem_state == MEM_OSHL_PM | next_mem_state == MEM_OSDE_PM | next_mem_state == MEM_OS_HL_N | next_mem_state == MEM_IOS_C | next_mem_state == MEM_IOS_N ; //-------1---------2---------3--------State Machines-------6---------7---------8---------9--------0 // we do this just to save virtual paper below. // IMPORTANT next_dec_state -- gets registered - mostly used in next tick. // next_mem_state --- gets further decoded -- lots of terms - most related to next tick // next_pipe_state - generall represents enables for regs on trailing edge of this tick // // 6 5 4 15 assign {next_dec_state, next_mem_state, next_pipe_state} = next_state; always @(ir1 or wb_int or inst_haz or dec_state or mem_exec_dec or cb_mem or ed_nn or ed_blk_cp or ed_blk_in or ed_blk_out or ed_retn or ed_blk_mv or ed_dbl_rd or blk_done or fr or jmpr_true or callnn_true or jmpnn_true or ed_rmw or ed_in_reg or blk_cpi_done or jmpr or ex_tos_hl or ed_out_reg) begin case (dec_state) DEC_IDLE: next_state = {DEC_IF1, MEM_NOP, IPIPE_NOP}; DEC_HALT: if (wb_int) next_state = {DEC_INT1,MEM_NOP ,IPIPE_NOP};// stay here until interrupt or reset else next_state = {DEC_HALT,MEM_NOP ,IPIPE_NOP}; DEC_IF1 : next_state = {DEC_IF2 ,MEM_IFPP1 ,IPIPE_NOP}; DEC_IF2 : next_state = {DEC_EXEC,MEM_IFPP1 ,IPIPE_EN1}; DEC_IF2A: next_state = {DEC_EXEC,MEM_IFPP1 ,IPIPE_NOP}; DEC_EXEC: if (inst_haz) next_state = {DEC_IF1, MEM_DECPC , IPIPE_NOP}; else if (wb_int) next_state = {DEC_INT1,MEM_NOP ,IPIPE_NOP}; else case (mem_exec_dec) // full case but can all tools understand ? just make a default I1_CB : next_state = {DEC_CB, MEM_IFPP1, IPIPE_EN1};// IF2_NOP -> nn <= (MEM) I1_DDFD : next_state = {DEC_DDFD, MEM_IFPP1, IPIPE_EN1};// gets real inst I1_ED : next_state = {DEC_ED, MEM_IFPP1, IPIPE_EN1}; I1_JMP : next_state = {DEC_IF2, MEM_JMPHL, IPIPE_NOP}; I1_N : next_state = {DEC_N, MEM_IFPP1, IPIPE_ENNEN2}; I1_NN : next_state = {DEC_NN, MEM_IFPP1, IPIPE_ENN}; I1_OF : next_state = {DEC_OF, MEM_OF1, IPIPE_EN12};//transfer, don't activate I1_OS : next_state = {DEC_IF2A, MEM_OS1, IPIPE_EN1}; // -> ir2_NOP I1_POP : next_state = {DEC_POP, MEM_OFSP, IPIPE_EN12}; I1_PUSH : next_state = {DEC_PUSH, MEM_OSSP, IPIPE_EN12}; I1_RET : next_state = {DEC_RET, MEM_OFSP, IPIPE_EN12}; I1_RMW : next_state = {DEC_RMW, MEM_OF1, IPIPE_EN12};//can't gronk ir1 - blow off if I1_RST : next_state = {DEC_NNCALL2, MEM_OSSP_PCM2, IPIPE_NOP}; I1_R2R : next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; I1_JMPR : next_state = {DEC_N, MEM_NOP, IPIPE_ENNEN2A2}; I1_HALT : next_state = {DEC_HALT, MEM_NOP , IPIPE_EN2}; default : next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; //I1_R2R endcase DEC_CB: if (cb_mem) next_state = {DEC_CBM, MEM_OF1, IPIPE_EN12}; else next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; DEC_DDFD: // except for CB and EB these all act the same H and L get modified by prefix case (mem_exec_dec) I1_CB : next_state = {DEC_PFxCB,MEM_IFPP1, IPIPE_ENN};// IF2_NOP -> nn <= (MEM) I1_DDFD : next_state = {DEC_DDFD, MEM_IFPP1, IPIPE_EN1}; I1_ED : next_state = {DEC_ED, MEM_IFPP1, IPIPE_EN1};//How do we clear the prefix? I1_JMP : next_state = {DEC_IF2, MEM_JMPHL, IPIPE_NOP}; I1_N : next_state = {DEC_DDN, MEM_IFPP1, IPIPE_ENN}; I1_NN : next_state = {DEC_NN, MEM_IFPP1, IPIPE_ENN}; I1_OF : next_state = {DEC_DDOF, MEM_IFPP1, IPIPE_ENN}; // d to nn - need to get d // LD A,(BC) LD A,(DE) will // become ix+d - do we care ? // i hope not // 5/13/04 the dd mods the index op // but NOT the operand -- gotta kill // the prefix on these I1_OS : next_state = {DEC_DDOS, MEM_IFPP1, IPIPE_ENN}; // d to nn I1_POP : next_state = {DEC_POP, MEM_OFSP, IPIPE_EN12}; I1_PUSH : next_state = {DEC_PUSH, MEM_OSSP, IPIPE_EN12}; I1_RET : next_state = {DEC_RET, MEM_OFSP, IPIPE_EN12}; I1_RMW : next_state = {DEC_RMWDD1, MEM_IFPP1, IPIPE_ENNEN2}; I1_RST : next_state = {DEC_NNCALL2, MEM_OSSP_PCM2, IPIPE_NOP}; // just dump next inst I1_R2R : next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; //I1_R2R I1_JMPR : next_state = {DEC_N, MEM_NOP, IPIPE_ENNEN2A2}; I1_HALT : next_state = {DEC_HALT, MEM_NOP , IPIPE_EN2}; default : next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; //I1_R2R endcase DEC_ED: if (ed_nn) next_state = {DEC_EDNN1, MEM_IFPP1, IPIPE_ENNEN2}; // we need to set inc and io and repeat flags on this state for continued block // processing -- keep the states of this machine somewhat manageable. else if (ed_rmw ) next_state = {DEC_RMW, MEM_OF1, IPIPE_EN12}; // RLD RRD else if (ed_blk_cp ) next_state = {DEC_EDBCP1, MEM_OFHL_PM, IPIPE_EN12};// MEM_OFHL_PM triggers --BC else if (ed_blk_in ) next_state = {DEC_EDBIN1, MEM_IOF_C, IPIPE_EN12};// MEM_IOF_C triggers --B else if (ed_blk_out) next_state = {DEC_EDBOUT1,MEM_OFHL_PM, IPIPE_EN12}; else if (ed_blk_mv ) next_state = {DEC_EDBMV1, MEM_OFHL_PM, IPIPE_EN12}; else if (ed_retn ) next_state = {DEC_RET, MEM_OFSP, IPIPE_EN12};// see int logic below else if (ed_in_reg ) next_state = {DEC_EDRD2, MEM_IOF_C, IPIPE_EN12}; else if (ed_out_reg ) next_state = {DEC_IF2A, MEM_IOS_C, IPIPE_EN12}; else next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; // double register reads and writes here DEC_EDNN1: next_state = {DEC_EDNN2, MEM_IFPP1, IPIPE_ENN}; // address to nn DEC_EDNN2: if (ed_dbl_rd) next_state = {DEC_EDRD1, MEM_OFNN, IPIPE_EN12}; else next_state = {DEC_EDWR, MEM_OSNN, IPIPE_EN12};// OSNN selects data ok? DEC_EDRD1: next_state = {DEC_EDRD2, MEM_OFADRP1, IPIPE_ENN}; // 1st byte 2n DEC_EDRD2: next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_ENNA2}; // 2nd byte 2nn DEC_EDWR: next_state = {DEC_IF2A, MEM_OSADRP1, IPIPE_NOP}; // ED block compair // Got a tricky problem here..... fr is updated in a different manner for cpi and // we really can't test blk_done here (bc is updated on this tick). So make the test // for done be bc==1 and use enna2 for everything. Course this begs the question if // this approach is not best for all block moves ????? DEC_EDBCP1: if (blk_cpi_done) next_state = {DEC_EXEC, MEM_IFPP1,IPIPE_ENNA2}; else if(wb_int) next_state = {DEC_INT1, MEM_NOP, IPIPE_ENNA2}; else next_state = {DEC_EDBCP2, MEM_NOP, IPIPE_ENNA2};//set flags DEC_EDBCP2: next_state = {DEC_EDBCP3, MEM_NOP, IPIPE_NOP};//wait for fr. alu_out is slow DEC_EDBCP3: if (fr[6]) next_state = {DEC_EXEC , MEM_IFPP1, IPIPE_NOP}; else next_state = {DEC_EDBCP1, MEM_OFHL_PM, IPIPE_NOP}; DEC_EDBIN1: next_state = {DEC_EDBIN2, MEM_NOP, IPIPE_ENN}; DEC_EDBIN2: if (blk_done) next_state = {DEC_IF2A, MEM_OSHL_PM,IPIPE_NOP}; // implies nn else if (wb_int) next_state = {DEC_INT1, MEM_OSHL_PM,IPIPE_NOP}; else next_state = {DEC_EDBIN3,MEM_OSHL_PM,IPIPE_NOP};//set flags DEC_EDBIN3: next_state = {DEC_EDBIN1, MEM_IOF_C, IPIPE_NOP}; DEC_EDBOUT1: next_state = {DEC_EDBOUT2, MEM_NOP, IPIPE_ENN}; DEC_EDBOUT2:if (blk_done) next_state = {DEC_IF2A, MEM_IOS_C,IPIPE_NOP}; else if (wb_int) next_state = {DEC_INT1, MEM_IOS_C,IPIPE_NOP}; // DEC_EDBOUT: if (blk_rpt) else next_state = {DEC_EDBOUT3,MEM_IOS_C,IPIPE_NOP}; DEC_EDBOUT3: next_state = {DEC_EDBOUT1,MEM_OFHL_PM, IPIPE_NOP}; DEC_EDBMV1: next_state = {DEC_EDBMV2, MEM_NOP, IPIPE_ENN}; DEC_EDBMV2: if (blk_done) next_state = {DEC_IF2A, MEM_OSDE_PM,IPIPE_NOP}; else if (wb_int) next_state = {DEC_INT1, MEM_OSDE_PM,IPIPE_NOP}; //DEC_EDBOUT: if (blk_rpt) else next_state = {DEC_EDBMV3,MEM_OSDE_PM,IPIPE_NOP}; DEC_EDBMV3: next_state = {DEC_EDBMV1,MEM_OFHL_PM, IPIPE_NOP}; DEC_N: if (INsA_6N7== ir1) next_state = {DEC_NIN, MEM_IOF_N, IPIPE_EN12}; else if (OUTs6N7_A==ir1) next_state = {DEC_IF2A, MEM_IOS_N, IPIPE_EN1}; else if (LDs6HL7_N==ir1) next_state = {DEC_IF2A, MEM_OS_HL_N, IPIPE_EN12}; else if (jmpr_true) next_state = {DEC_IF1, MEM_REL2PC, IPIPE_NOP}; else if (jmpr) next_state = {DEC_IF2, MEM_IFPP1, IPIPE_NOP}; else next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2};//r2r DEC_DDN: if (INsA_6N7== ir1) next_state = {DEC_NIN, MEM_IOF_N, IPIPE_EN12}; else if (OUTs6N7_A==ir1) next_state = {DEC_IF2A, MEM_IOS_N, IPIPE_EN1}; else if (LDs6HL7_N==ir1) next_state = {DEC_IF1, MEM_OSIXpD, IPIPE_ENN}; else next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2};//r2r //DEC_NIN: next_state = {DEC_IF2, MEM_IFPP1, IPIPE_ENNA2}; // bjp 10/11/2007 have ir1 set - next inst gets started should goto DEC_EXEC DEC_NIN: next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_ENNA2}; //ISSUES: LDsSP_NN - load commanded from ir2 decode? and mechaninsm for updating PC on // JMP and CALL // on CALL We have IFNN for JMP // For CALL Use MEM_CALL to transfer pc<=nn, nn<=pc, adr<=sp then MEM_OSSP then IFPP1 // For LDsSP_NN yes update from ir2 decode. DEC_NN: if (callnn_true) next_state = {DEC_NNCALL1, MEM_NOP, IPIPE_ENN};// this gets new adr in nn //if we store from nn we can't do // a mem op now else if (jmpnn_true) next_state = {DEC_NNJMP, MEM_NOP, IPIPE_ENN}; // gotta get nn before we can // transfer to adr. else if (LDs6NN7_A==ir1) next_state = {DEC_NNOS3, MEM_IFPP1, IPIPE_ENN}; else if (LDs6NN7_HL==ir1) next_state = {DEC_NNOS1, MEM_IFPP1, IPIPE_ENN}; else if (LDsA_6NN7==ir1) next_state = {DEC_NNOF3, MEM_IFPP1, IPIPE_ENN}; else if (LDsHL_6NN7==ir1) next_state = {DEC_NNOF1, MEM_IFPP1, IPIPE_ENN}; else next_state = { DEC_IF2, MEM_IFPP1, IPIPE_ENNEN2A2}; DEC_NNCALL1: next_state = {DEC_NNCALL2, MEM_CALL , IPIPE_NOP}; DEC_NNCALL2: next_state = {DEC_IF1, MEM_OSSP, IPIPE_NOP};//A1 activates r2r xfers from ir1 DEC_NNJMP: next_state = {DEC_IF2, MEM_IFNN , IPIPE_NOP}; // ISSUE: we blow out ir1 here - so need to keep some status to execute OSNN2. // general solution if not DEC_EXEC we get op frmo nn high byte. // note that first MEM_OSNN trabsferrs nn to wb_adr_o. DEC_NNOS1: next_state = {DEC_NNOS2, MEM_OSNN, IPIPE_EN1}; DEC_NNOS2: next_state = {DEC_IF2A, MEM_OSADRP1, IPIPE_NOP}; DEC_NNOS3: next_state = {DEC_IF2A, MEM_OSNN, IPIPE_EN1}; DEC_NNOF1: next_state = {DEC_NNOF2, MEM_OFNN, IPIPE_EN12}; DEC_NNOF2: next_state = {DEC_NNOF4, MEM_OFADRP1, IPIPE_ENN}; DEC_NNOF3: next_state = {DEC_NNOF4, MEM_OFNN, IPIPE_EN12}; DEC_NNOF4: if (ex_tos_hl) next_state = {DEC_EXSPHL, MEM_NOP, IPIPE_ENNA2}; else next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_ENNA2}; DEC_DDOS: next_state = {DEC_IF2A, MEM_OSIXpD, IPIPE_EN12}; DEC_DDOF: next_state = {DEC_OF , MEM_OFIXpD, IPIPE_EN12}; DEC_OF: next_state = {DEC_EXEC, MEM_IFPP1 , IPIPE_ENNA2}; DEC_POP: next_state = {DEC_NNOF4, MEM_OFSP, IPIPE_ENN }; DEC_PUSH: next_state = {DEC_IF2A , MEM_OSSP, IPIPE_NOP }; DEC_RET: next_state = { DEC_RET2, MEM_OFSP, IPIPE_ENN }; DEC_RET2: next_state = { DEC_NNJMP, MEM_NOP, IPIPE_ENN }; // blow off a tick so we don't gronk adr DEC_RMW: next_state = {DEC_RMW2, MEM_NOP, IPIPE_ENNA2}; //activate DEC_RMW2: next_state = {DEC_IF2A , MEM_OSADR, IPIPE_NOP }; // from nn // IF memory -- rmw else these are all reg 2 reg DEC_CBM: if (CB_BIT==ir1[9:6]) next_state = {DEC_IF2, MEM_IFPP1, IPIPE_ENNA2}; else next_state = {DEC_RMW2 , MEM_NOP, IPIPE_ENNA2}; // The DDCB anf FDCB all assume memory operands // These beauties always rmw memory. If a register op is default, they also // update the register. Programmers think of this as 2 ops for the price of 1. // unfortunately it is 2 ops for the price of 4.-- its not the number of lines // of assembler code that count but the number of bytes assembled. Oh well I signed // up for this...... and had a notion of what I was getting into. // DEC_PFxCB: next_state = { DEC_PFxCB2, MEM_IFPP1, IPIPE_EN1}; // this gets inst DEC_PFxCB2: next_state = { DEC_PFxCB3, MEM_OFIXpD, IPIPE_EN12}; //next inst - get op DEC_PFxCB3: next_state = { DEC_PFxCB4, MEM_NOP, IPIPE_ENNA2}; DEC_PFxCB4: next_state = { DEC_IF2A, MEM_OSADR, IPIPE_NOP}; //execute ir2 // crap gotta subtract 2 (we always increment pc 2 times relative to the inst // that got interrupted. also can't push and dec pc without 2 adders. // choices: 1) fix up pc in 2 ticks 2) fix in 1 tick 3) add adder and do it fast // if there's anyone who knows is there anyone who cares. // guess I'll do it fast -- just a 16 bit subtractor. heck silicon is // cheap. DEC_INT1: next_state = {DEC_INT2, MEM_OSSP_PCM2, IPIPE_NOP}; //must derement PC DEC_INT2: next_state = {DEC_INT3, MEM_OSSP, IPIPE_NOP}; //was MEM_OSSP_P why? comment out DEC_INT3: next_state = {DEC_INT4, MEM_INTA, IPIPE_NOP}; DEC_INT4: next_state = {DEC_INT5, MEM_NOP, IPIPE_ENN}; DEC_INT5: next_state = {DEC_INT6, MEM_IFINT, IPIPE_NOP}; // really a pointer fetch - but treat a a jmpnn DEC_INT6: next_state = {DEC_RET2, MEM_IFPP1, IPIPE_ENN}; DEC_EXSPHL: next_state = {DEC_PUSH, MEM_OSSP, IPIPE_NOP}; DEC_RMWDD1: next_state = {DEC_RMW, MEM_OFIXpD, IPIPE_EN1}; default: next_state = {DEC_IDLE, MEM_NOP, IPIPE_NOP}; endcase end always @(posedge wb_clk_i or posedge rst_i) if (rst_i) dec_state <= DEC_IDLE; else if (wb_rdy_nhz ) dec_state <= next_dec_state; //-----------------------instruction register #1 ---------------------------------- // // next_pipe_state {ir1,ir2,nn,act_ir2} wire update_prefix = dec_state == DEC_EXEC | dec_state == DEC_DDFD | dec_state == DEC_PFxCB; wire iext_ed = update_prefix & (ir1[7:0]==8'hed); wire iext_cb = update_prefix & (ir1[7:0]==8'hcb); always @(posedge wb_clk_i or posedge rst_i) if (rst_i) ir1 <= NOP; else if (wb_rdy_nhz & next_pipe_state[3]) ir1 <= {iext_ed, iext_cb, wb_dat_i} ; //----------- prefix states ----------------------------------------- // strings of prefix insts are ignored up to last one. Also dded and fded are ignored // but ddcd and fdcd are defined prefix sets. // always @(posedge wb_clk_i) if (wb_rdy_nhz & next_dec_state == DEC_EXEC) {ir1dd, ir1fd } <= 2'b0; else if ( wb_rdy_nhz & update_prefix ) {ir1dd, ir1fd } <= { (ir1[7:0]==8'hdd ) | ir1dd & (ir1[7:0]!=8'hed) & (ir1[7:0]!=8'hfd), (ir1[7:0]==8'hfd ) | ir1fd & (ir1[7:0]!=8'hed) & (ir1[7:0]!=8'hdd) }; //------------------- inst reg #2 ----------------------------------- // This stuff is key to the data hazard logic. Hazards arise only AFTER activation of // a previous instruction. Fundamentally all state changes related to ir1 may be // delayed eithor by a delay in wb response, or by a hazard. Ir2 state changes // are keyed off exec_ir2 - and always happen immediately. ( exec_ir2 always is // immediately reset - unless of course a new instruction is transferred and executed. // // // always @(posedge wb_clk_i or posedge rst_i) if (rst_i) ir2 <= 10'h0; else if (wb_rdy_nhz & next_pipe_state[2]) ir2 <= ir1; wire kill_prefix = next_mem_state == MEM_OFIXpD; always @(posedge wb_clk_i or posedge rst_i) if (rst_i) begin ir2dd <= 1'b0; ir2fd <= 1'b0; end else if (wb_rdy_nhz & next_pipe_state[2]) begin ir2dd <= ir1dd & ~kill_prefix; ir2fd <= ir1fd & ~kill_prefix; end always @(posedge wb_clk_i ) if (wb_rdy_nhz & next_pipe_state[0]) exec_ir2 <= 1'b1; else exec_ir2 <= 1'b0; //-------------- special instruction flag --------------------------- // need this because the POP flow we use gronks ir1 early. I guess we could use // ir2, but keeping the dec_state sequencer independent from ir2 seems like a good idea. // always @(posedge wb_clk_i) if ((dec_state == DEC_EXEC) | (dec_state == DEC_DDFD)) ex_tos_hl <= (ir1 == EXs6SP7_HL); //--------------- block move flags ------------------------ always @(posedge wb_clk_i) if (dec_state == DEC_ED) blk_inc_flg <= dec_blk_inc; else if (dec_state == DEC_EXEC) blk_inc_flg <= 1'b0; always @(posedge wb_clk_i) if (dec_state == DEC_ED) blk_rpt_flg <= dec_blk_rpt; else if (dec_state == DEC_EXEC) blk_rpt_flg <= 1'b0; else if (dec_state == DEC_INT1) blk_rpt_flg <= 1'b0; always @(posedge wb_clk_i) if (dec_state == DEC_ED) blk_io_flg <= dec_blk_io; else if (dec_state == DEC_EXEC) blk_io_flg <= 1'b0; //-------------------------- memory interface stuff ---------------------------- // -- wb_adr_o 4/30/04 to wb_rdy_nhz -- hazard gronks this otherwise always @(posedge wb_clk_i) if (wb_rdy_nhz) wb_adr_o <= mux21; // -- wb_we_o; always @(posedge wb_clk_i or posedge rst_i) if (rst_i) wb_we_o <= 1'b0; else if (wb_rdy_nhz) wb_we_o <= we_next; // -- wb_cyc_o // below is old logic -- appears not needed //wire no_wb_start = mem_idle | mem_halt | mem_op3 & blk_cmp_reg | mem_op1 & rmw_reg; wire no_mem_start = (next_mem_state == MEM_NOP) | (next_mem_state == MEM_REL2PC); always @(posedge wb_clk_i or posedge rst_i) if (rst_i) wb_cyc_o <= 1'b0; else if (wb_rdy_nhz) wb_cyc_o <= ~no_mem_start; // -- wb_stb_o; always @(posedge wb_clk_i or posedge rst_i) if (rst_i) wb_stb_o <= 1'b0; else if (wb_rdy_nhz) wb_stb_o <= ~no_mem_start ; // -- wb_lock lets not worry about lock unless somebody thinks it matters. // -- wb_tga_o always @(posedge wb_clk_i or posedge rst_i) if (rst_i) wb_tga_o <= 2'b0; else if (wb_rdy_nhz) begin if (next_mem_state == MEM_IOF_C | next_mem_state == MEM_IOS_C | next_mem_state == MEM_IOF_N | next_mem_state == MEM_IOS_N ) wb_tga_o <= TAG_IO; else if (next_mem_state == MEM_INTA ) wb_tga_o <= TAG_INT; else wb_tga_o <= 2'b0 ; end //------------ the input-output data register (nn) ----------------------------------------- // basicaly we store lsb's folowed by msb's // input is always to msb (of input regiser) first (if a 2 byte operand, lsb<=msb before transfer) // this gets nn to position { msb, lsb } before we execute 2 byte transfer. // // if we don't update - we byte swap as well as // when we read // IMPORTANT We store from MSB's so that on block moves read and write from same place. // this makes the output look somewhat bass-ackwards but who is looking? // // There is probably a simpler way to do this. Unfortunately there are a lot of // dependencies here. Ill continue as planned till it proves untractable. // Issue is that we are using ir1 to provide the op specification -- but in general // ir1 gets gronked before 2nd store (if it happens) - so we need to capture both // data first time OSIXpD OS1 OSSP, and MEM_OSNN // // on consideration lets make a flag flag_firstos that gets set on first store after // DEC_EXEC // ISSUE reads both here and in ir1 need to execute on wb_ack_i ? // I recall wb_ack_i must stay active until a change in cycle ? // need to review wb spec. // //issue: how is EXs6SP7_HL implemented -- it is known as a rmw - and only trick for this file is // that nn must be properly updates with ir2 // 5/17/04 Sure didn't get EXs6SP7_HL right first time through. After some serious thought // decided to hop onto the POP flow with this --- POP - exchange - PUSH biggest trick // is modified SP updating. // 4/30/04 changed else if (we_next) we had a hazard and this term // seemed to be gronking nn. see if it works now. Pretty tricky stuff. always @(posedge wb_clk_i or posedge rst_i) if (rst_i) flag_os1 <= 1'b0; else if ((DEC_EXEC == next_dec_state) & wb_rdy) flag_os1 <= 1'b0; else if ( we_next & wb_rdy_nhz ) flag_os1 <= 1'b1; wire ir2_cb_shift = (ir2[9:6] == 4'b01_00) ; // I'll hand or the 8 defined terms here wire ir2_cb_bit = (ir2[9:6] == CB_RES ) | (ir2[9:6] == CB_SET ) ; wire [15:0] dec_const = (DEC_INT1 == dec_state) & blk_rpt_flg ? 16'h3 : (DEC_INT1 == dec_state) ? 16'h2 : 16'h1 ; wire [15:0] pc_123 = pc - dec_const; // bjp comment -- logic here is getting pretty slow --- the else if's are out of // line need to get this cleaned up for synthesis -- but first get it logically // correct. always @(posedge wb_clk_i or posedge rst_i) if (rst_i) nn <= 6'h00; else if (wb_rdy_nhz) begin // This term forces the second store data in any flow to be from nn[7:0] // LOL better not do this for block repeat flows if ( we_next & flag_os1 & ~blk_rpt_flg) nn <= { nn[7:0], nn[15:8] } ; else if( next_mem_state == MEM_CALL) nn <= {pc}; else if( next_mem_state == MEM_OSSP_PCM2) nn <= {pc_123}; else if(EXs6SP7_HL== ir2 & ir2dd & exec_ir2) nn <= ixr; else if(EXs6SP7_HL== ir2 & ir2fd & exec_ir2) nn <= iyr; else if(EXs6SP7_HL== ir2 & exec_ir2) nn <= hl; else if((INCs6HL7==ir2 | DECs6HL7==ir2) & exec_ir2) nn[15:8] <= alu8_out; else if( ir2_cb_shift & MEM_OSADR == next_mem_state ) nn[15:8] <= sh_alu; else if( ir2_cb_bit & MEM_OSADR == next_mem_state ) nn[15:8] <= bit_alu; else if( ED_RRD == ir2 & MEM_OSADR == next_mem_state) nn[15:8] <= {ar[3:0], nn[15:12]}; else if( ED_RLD == ir2 & MEM_OSADR == next_mem_state) nn[15:8] <= {nn[11:8], ar[3:0] }; else if (next_pipe_state[1]) nn <= { wb_dat_i, nn[15:8] }; // ENN overides os stuff // these are the general cases with ir1 providing register specification // let PUSH have priority (we need os_h for some indexed stores under ir1dd) else if (we_next & ir1 == PUSHsHL) nn <= hl_or_ixiy; // use for PUSHsHL else if(we_next & ( next_mem_state == MEM_OS1 | next_mem_state == MEM_OSIXpD | next_mem_state == MEM_OSSP | next_mem_state == MEM_IOS_N | next_mem_state == MEM_IOS_C | next_mem_state == MEM_OSNN ) ) // oh my god -- operands go out in different order to stack than they // do to normal stores. Oh well, guess that makes ordering consistent in // memory begin if (os_a) nn <= {ar, fr }; // use for PUSHsAF if (os_b) nn <= {br, cr }; // use for PUSHsBC if (os_c) nn[15:8] <= cr; if (os_d) nn <= {dr, er }; // use for PUSHsDE if (os_e) nn[15:8] <= er; if (os_h) nn <= {hr, lr }; if (os_l) nn[15:8] <= lr; if (os_bc) nn <= {cr, br }; if (os_de) nn <= {er, dr }; if (os_sp) nn <= {sp[7:0], sp[15:8] }; if (os_hl) nn <= {lr, hr }; if (os_ixr) nn <= {ixr[7:0], ixr[15:8] }; if (os_iyr) nn <= {iyr[7:0], iyr[15:8] }; end // 4/19/2004 previously no if here - if not needed we don't need next_pipe_state[1] eithor end //------------------- pc and sp ---------------------------------------------------- always @(posedge wb_clk_i or posedge rst_i) if (rst_i) pc <= 16'h0; else if (wb_rdy_nhz) begin if (next_mem_state == MEM_DECPC) pc <= pc - 16'h1; // decrementer could perhaps be shared. if (next_mem_state == MEM_IFPP1) pc <= adr_alu; if (next_mem_state == MEM_CALL ) pc <= nn; //Use MEM_CALL to exchange pc<=>nn if (next_mem_state == MEM_RST) pc <= adr_alu; if (next_mem_state == MEM_JMPHL) pc <= adr_alu; if (next_mem_state == MEM_OSSP_PCM2) pc <= { 10'h0, ir1[5:3], 3'h0} ; if (next_mem_state == MEM_IFNN ) pc <= adr_alu; //on jumps get adr+1 in pc immediately. if (next_mem_state == MEM_REL2PC) pc <= adr_alu; if (next_mem_state == MEM_IFINT) pc <= adr_alu; // like a jump need adr+1 here end //---------------------------------- sp ----------------------------------------------------- // // with pc updates are always made from ir1 as the PC is so critical to instruction flow. // (this of course creates the possibility of an "inst_hazard" - where data is stored in an // instruction already fetched - see below) // with sp the situation is not so simple. // Issues - especially regarding hazards. // // LDsSP_NN this should be done from ir2 - no hazard as active state is ALWAYS IF2 // // ADDsHL_SP The add is a pre-add so sp cannot be modified before inst is executed from ir2 // DECsSP Just do it with ir1 at DEC_EXEC gotcha need -- IFPP1 in general use ir2 -> hazard // EXs6SP7_HL rmw - no change to sp - no issue here // INCsSP Just do it with ir1 at DEC_EXEC gotcha -- IFPP1 use ir2 -> hazard // LDsSP_HL do from ir1 and use standard hazard logic (if H or L is being // updated -- wait) // // ED_LDs6NN7_REG REG== SP // needs to be done from ir2 // ED_LDsREG_6NN7 REG== SP // do from ir2 - no hazard as executed on IF2 - refill pipe wire ed_ld_spreg = (ED_LDsREG_6NN7 == {ir2[9:6],ir2[3:0]}) & (ir2[5:4] == DBL_REG_SP); always @(posedge wb_clk_i ) begin if (exec_ir2 ) // this has priority of course begin if (LDsSP_NN == ir2) sp <= nn; if (ed_ld_spreg) sp <= nn; if ( DECsSP == ir2 ) sp <= add16; if ( INCsSP == ir2 ) sp <= add16; end if (wb_rdy_nhz) //the no hazard term should kill these if any abvove is happening in parallel begin if ( LDsSP_HL == ir1 & dec_state == DEC_EXEC) sp <= hl_or_ixiy; if ( LDsSP_HL == ir1 & dec_state == DEC_DDFD) sp <= hl_or_ixiy; if (next_mem_state == MEM_OFSP ) sp <= adr_alu; if (next_mem_state == MEM_OSSP ) sp <= adr_alu; if (next_mem_state == MEM_OSSP_PCM2 ) sp <= adr_alu; //if (next_mem_state == MEM_OSSP_P ) sp <= adr_alu; if (next_mem_state == MEM_CALL ) sp <= adr_alu; end end //-------------------- int logic ---------------------------------------- // We have a wishbone interrupt system - which i guess does not preclude a // non-maskable interrupt...... but bottom line is that such an interrupt is // definately out of favor with current system thinking. Within an embedded system // ( the target application here ) a single interrupt controller capable of handeling // as many interrupts as desired is the best choice. // Therefore we enable only mode 2 interrupts and a single enable ff. // // This begs the question of what to do with the "RETI" instruction -- ED4D. We opt to // enable interrupts with this instruction (and all its "aliases"). // always @(posedge wb_clk_i or posedge rst_i) if (rst_i) int_en <= 1'b0; else if (wb_rdy_nhz) begin if ((dec_state == DEC_EXEC) & (DI== ir1)) int_en <= 1'b0; else if ((dec_state == DEC_EXEC) & en_int_next) int_en <= 1'b1; if (dec_state == DEC_INT1) int_en <= 1'b0; end always @(posedge wb_clk_i or posedge rst_i) if (rst_i) en_int_next <=1'b0; else if (wb_rdy_nhz) begin if ((dec_state == DEC_EXEC) & (EI== ir1)) en_int_next <=1'b1; else if ((dec_state == DEC_RET ) & (ED_RETI == ir2)) en_int_next <=1'b1; else if (dec_state == DEC_EXEC) en_int_next <=1'b0; end always @(posedge wb_clk_i) wb_irq_sync <= int_req_i; assign wb_int = wb_irq_sync & int_en; endmodule
Go to most recent revision | Compare with Previous | Blame | View Log