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