Design an 8-bit Processor with Verilog at Behavioral Level We use the Intel 8085 all time popular 8-bit processor as an example. A complete functional Verilog model for the Intel 8085 will be presented. Lecture outline 1. review the architecture, chip layout, pin definition 2. instruction set 3. 8085 Verilog models 4. 8085 Verilog test bench. 1 2 Architecture of the 8085 The 8085 has: A 16-bit program counter (PC) A 16-bit stack pointer (SP) An 8-bit instruction register An 8-bit accumulator Six 8-bit general purpose registers, B, C, D, E, H, L BC, DE, HL can be accessed in pairs or individually. A temporary register pair: W, Z Instructions are 1 to 3 bytes in length and the first byte is the OPCODE Seven different machine cycles (each machine cycle may take up to 4 clock cycles) 1. opcode fetch 2. memory read 3. memory write 4. I/O read 5. I/O write 6. interrupt acknowledge 7. bus idle 3 4 S0, S1 (Output) Data Bus Status. Encoded status of the bus cycle: S1 S0 0 0 0 1 1 0 1 1 HALT WRITE READ FETCH RD (Output 3state) READ; indicates the selected memory or I/O device is to be read and that the Data Bus is available for the data transfer. 3stated during Hold and Halt. WR (Output 3state) WRITE; indicates the data on the Data Bus is to be written into the selected memory or I/O location. 3stated during Hold and Halt modes. 5 READY (Input) If Ready is high during a read or write cycle, it indicates that the memory or peripheral is ready to send or receive data. If Ready is low, the CPU will wait for Ready to go high before completing the read or write cycle. HOLD (Input) HOLD; indicates that another Master is requesting the use of the Address and Data Buses. The CPU, upon receiving the Hold request. will relinquish the use of buses as soon as the completion of the current machine cycle. Internal processing can continue. The processor can regain the buses only after the Hold is removed. When the Hold is acknowledged, the Address, Data, RD, WR, and IO/M lines are 3stated. 6 HLDA (Output) HOLD ACKNOWLEDGE; indicates that the CPU has received the Hold request and that it will relinquish thebuses in the next clock cycle. HLDA goes low after the Hold request is removed. The CPU takes the buses one half clock cycle after HLDA goes low. RESTART INTERRUPTS; These three inputs have the same timing as INTR except they cause an internal RESTART to be automatically inserted. RST 7.5 Highest Priority RST 6.5 RST 5.5 Lowest Priority The priority of these interrupts is ordered as shown above. These interrupts have a higher priority than the INTR. 7 TRAP (Input) Trap interrupt is a nonmaskable restart interrupt. It is recognized at the same time as INTR. It is unaffected by any mask or Interrupt Enable. It has the highest priority of any interrupt. Name RESTART Address (Hex) TRAP RST 5.5 RST 6.5 RST 7.5 2416 2C16 3416 3C16 RESET IN (Input) Reset sets the Program Counter to zero and resets the Interrupt Enable and HLDA flip flops. 8 IO/M (Output) IO/M indicates whether the Read/Write is to memory or l/O Tristated during Hold and Halt modes. RESET OUT (Output) Indicates CPU is being reset. Can be used as a system RESET. The signal is synchronized to the processor clock. X1, X2 (Input) Crystal or R/C network connections to set the internal clock generator X1 can also be an external clock input instead of a crystal. The input frequency is divided by 2 to give the internal operating frequency. CLK (Output) Clock Output for use as a system clock 9 module s85; // simulation testbench module reg [8:1] dflags; initial dflags = 0; // diag flags: // 1 = printmem // 2 = dump state at end // 3 = test reset control // 4 = monitor the transmit and receive lines wire s0, ale, rxd, txd, clock; tri[7:0] tri1 ad, a; read, write, iomout; reg trap, rst7p5, rst6p5, rst5p5, intr, ready, nreset, hold, pclock; 10 //instantiate the clock osc timebase(clock); //instantiate the RAM module ram85a r0(ale, ad, a, write, read, iomout); //instantiate the 8085a processor module intel_8085a i85(clock, , , , , trap, rst7p5, rst6p5, rst5p5, intr, , ad, a, s0, ale, write, read, , iomout, ready, nreset, , , hold); initial begin $write("\n"); ….. ….. endmodule 11 module intel_8085a (clock, x2, resetff, sodff, sid, trap, rst7p5, rst6p5, rst5p5, intr, intaff, ad, a, s0, aleff, writeout, readout, s1, iomout, ready, nreset, clockff, hldaff, hold); reg [8:1] dflags; initial dflags = 'b000; // diag flags: // 1 = trace instructions // 2 = trace IN and OUT instructions // 3 = trace instruction count output resetff, sodff, intaff, s0, aleff, writeout, readout, s1, iomout, clockff, hldaff; inout[7:0] ad, a; // a is address bus low byte output only input clock, x2, sid, trap, rst7p5, rst6p5, rst5p5, intr, ready, nreset, hold; 12 reg[15:0] pc, sp, addr; reg[8:0] intmask; reg[7:0] acc, regb, regc, regd, rege, regh, regl, ir, data; reg aleff, s0ff, s1ff, hldaff, holdff, // program counter // stack pointer // address output // interrupt mask and status // accumulator // general // general // general // general // general // general // instruction // data output // address latch enable // status line 0 // status line 1 // hold acknowledge // internal hold 13 intaff, trapff, trapi, inte, int, validint, haltff, resetff, clockff, sodff, read, write, iomff, acontrol, dcontrol, s, cs, cz, cac, cp, cc; // interrupt acknowledge // trap interrupt request // trap execution for RIM instruction (RIM:read interrupt mask) // previous state of interrupt enable flag // interrupt acknowledge in progress // interrupt pending // halt request // reset output // clock output // serial output data // read request signal // write request signal // i/o memory select // address output control // data output control // data source control // sign condition code // zero condition code // aux carry condition code // parity condition code // carry condition code 14 The condition flags Z Zero S Sign P Parity C Carry A Auxiliary carry Registers: A, B, C, D, E, H, L Register pairs: BC, DE, HL Symbols and abbreviations used in Assembly language accumulator Register A addr 16-bit address data 8-bit data data 16 16-bit data byte 2 the second byte of the instruction byte 3 the third byte of the instruction port 8-bit address of an I/O device r, r1, r2 one of the registers A, B, C, D, E, H, L DDD, SSS destination, source rp register pair ( ) the contents of the memory location or register enclosed in the parentheses 15 Overview of Instruction set 1. Data Transfer Group 2. Logic Group 3. Branch Group 4. Stack and Machine Control Group 5. Arithmetic Group Data Transfer Instructions IN port (A) (port) OUT port (port) (A) // move data at port to Accumulator // two byte instruction, first byte is OPCODE //second byte is port address //move data from A to port For examples IN 5 OUT 1 16 LDA addr (A) ((byte 3) (byte 2)) //load accumulator direct STA addr ((byte 3)(byte 2)) (A) //store accumulator direct example: LDA First STA First // First is a 16-bit address LHLD addr //load H and L direct (L) ((byte3) (byte 2)) (H) ((byte 3) (byte 2) + 1) SHLD addr //store H and L direct ((byte 3)(byte 2)) (L) ((byte 3)(byte 2) + 1) (H) MOV r, M (r) ((H)(L)) example MOV B, M //move from memory specified by HL //to a register r 17 MOV M, r //store r in memory LDAX rp (A) ((rp)) //load accumulator indirect STAX rp ((rp)) (A) //store accumulator indirect MVI r, data (r) (byte 2) //move immediate LXI rp, data 16 (rl) (byte 2) (rh) (byte 3) //load register pair immediate MVI M, data ((H)(L)) (byte 2) //move to memory immediate 18 Verilog Model Examples for Data Transfer Instructions /* move register to register */ task move; case(ir[2:0]) 0: rmov(regb); // MOV -,B 1: rmov(regc); // MOV -,C 2: rmov(regd); // MOV -,D 3: rmov(rege); // MOV -,E 4: rmov(regh); // MOV -,H 5: rmov(regl); // MOV -,L 6: if(ir[5:3] == 6) begin haltff = 1; // HLT end else begin // MOV -,M memread(data, {regh, regl}); rmov(data); end 7: rmov(acc); // MOV -,A endcase endtask 19 /* enabled only by move */ task rmov; input[7:0] fromreg; case(ir[5:3]) 0: regb = fromreg; // MOV B,1: regc = fromreg; // MOV C,2: regd = fromreg; // MOV D,3: rege = fromreg; // MOV E,4: regh = fromreg; // MOV H,5: regl = fromreg; // MOV L,6: memwrite(fromreg, {regh, regl}); // MOV M,7: acc = fromreg; // MOV A,endcase endtask 20 /* move register and memory immediate */ task movi; begin case(ir[5:3]) 0: memread(regb, pc); // MVI B, -1: memread(regc, pc); // MVI C, -2: memread(regd, pc); // MVI D, -3: memread(rege, pc); // MVI E, -4: memread(regh, pc); // MVI H, -5: memread(regl, pc); // MVI L, -6: // MVI M, -- ; ((H)(L)) <-- (byte 2) begin memread(data, pc); memwrite(data, {regh, regl}); end 7: memread(acc, pc); // MVI A endcase pc = pc + 1; end endtask 21 /* increment register and memory contents */ task inr; case(ir[5:3]) 0: doinc(regb); // INR B 1: doinc(regc); // INR C 2: doinc(regd); // INR D 3: doinc(rege); // INR E 4: doinc(regh); // INR H 5: doinc(regl); // INR L 6: // INR M begin memread(data, {regh, regl}); doinc(data); memwrite(data, {regh, regl}); end 7: doinc(acc); // INR A endcase endtask 22 /* enabled only from incrm */ task doinc; inout[7:0] sr; begin cac = sr[3:0] == 'b1111;//auxiliary carry is set least 4 bits = 1111 // i.e., ac is 1 when ----1111 is incremented //by one sr = sr + 1; calpsz(sr); end endtask /* calculate cp cs and cz */ task calpsz; input[7:0] tr; begin cp = ^tr; //parity, ^Exclusive or all bits of tr cz = tr == 0; //zero flag cs = tr[7]; //sign flag end endtask 23 /* store and load instruction */ task sta_lda; reg[15:0] ra; case(ir[5:3]) 0: memwrite(acc, {regb, regc}); // STAX B 1: memread(acc, {regb, regc}); // LDAX B 2: memwrite(acc, {regd, rege}); // STAX D 3: memread(acc, {regd, rege}); // LDAX D 4: // SHLD begin adread(ra); memwrite(regl, ra); memwrite(regh, ra + 1); end 5: // LHLD begin adread(ra); memread(regl, ra); memread(regh, ra + 1); end 24 6: // STA begin adread(ra); memwrite(acc, ra); end 7: // LDA begin adread(ra); memread(acc, ra); end endcase endtask /* fetch address from pc+1, pc+2 */ task adread; output[15:0] address; begin memread(address[7:0], pc); pc = pc + 1; memread(address[15:8], pc); if(!int) pc = pc + 1; // if interrupt is not true, pc = pc+1 end endtask 25 /* memory read */ task memread; output[7:0] rdata; input[15:0] raddr; begin @(posedge clock) addr = raddr; s = 0; acontrol = 1; dcontrol = 1; iomff = int; s0ff = int; s1ff = 1; aleff = 1; @(posedge clock) aleff = 0; @(posedge clock) dcontrol = 0; if(int) intaff = 0; else read = 0; @(posedge clock) ready_hold; checkint; @(posedge clock) intaff = 1; read = 1; rdata = ad; if(holdff) holdit; end endtask 26 /* memory write */ task memwrite; input[7:0] wdata; input[15:0] waddr; begin @(posedge clock) aleff = 1; s0ff = 1; s1ff = 0; s = 0; iomff = 0; addr = waddr; acontrol = 1; dcontrol = 1; @(posedge clock) aleff = 0; @(posedge clock) data = wdata; write = 0; s = 1; @(posedge clock) ready_hold; checkint; @(posedge clock) write = 1; if(holdff) holdit; end endtask 27 Logic and Arithmetic operations CMA (A) (A) CMC (CY) (CY) // complement the accumulator STC ANI data ANA r ANA M ORI ORA r ORA M XRI data XRA r XRA M CPI data CMP r CMP M // set the carry flag // AND immediate, A and with byte 2 // A and with register r // A and with memory // OR immediate, A or with byte 2 // A or with register r // A or with memory // Exclusive_OR immediate // A xor with register r // A xor with memory // compare immediate // compare register // compare memory // complement the carry flag 28 RLC rotate accumulator left (CY) A7; A0 A7; An+1 An RRC rotate accumulator right (CY) A0; A7 A0; An An+1 RAL RAR rotate left through carry rotate right through carry ADD r add register (A) (A) + (r) ADD M add memory ADI data add immediate ADC r add register with carry ADC M add memory with carry ACI data add immediate with carry SUB r subtract register SUB M subtract memory SUI data subtract immediate SBB r subtract register with borrow SBB M subtract memory with borrow 29 SBI data subtract immediate with borrow INR r INR M DCR r DCR M INX rp DCX rp increment register increment memory decrement register decrement memory increment register pair decrement register pair DAD rp DAA add register pair to H and L decimal adjust accumulator 30 /* operate on accumulator */ task doacci; input[7:0] sr; reg[3:0] null4; reg[7:0] null8; case(ir[5:3]) 0: // ADD ADI begin {cac, null4} = acc + sr; {cc, acc} = {1'b0, acc} + sr; calpsz(acc); end 1: // ADC ACI begin {cac, null4} = acc + sr + cc; {cc, acc} = {1'b0, acc} + sr + cc; calpsz(acc); end 2: // SUB SUI begin {cac, null4} = acc - sr; {cc, acc} = {1'b0, acc} - sr; calpsz(acc); end 3: // SBB SBI begin {cac, null4} = acc - sr - cc; {cc, acc} = {1'b0, acc} - sr - cc; calpsz(acc); end 4: // ANA ANI begin acc = acc & sr; cac = 1; cc = 0; calpsz(acc); end 31 5: // XRA XRI begin acc = acc ^ sr; cac = 0; cc = 0; calpsz(acc); end 6: // ORA ORI begin acc = acc | sr; cac = 0; cc = 0; calpsz(acc); end 7: // CMP CPI begin {cac, null4} = acc - sr; {cc, null8} = {1'b0, acc} - sr; calpsz(null8); end endcase endtask 32 /* rotate acc and special instructions */ task racc_spec; case(ir[5:3]) 0: // RLC begin acc = {acc[6:0], acc[7]}; cc = acc[7]; end 1: // RRC begin acc = {acc[0], acc[7:1]}; cc = acc[0]; end 2: // RAL {cc, acc} = {acc, cc}; 33 3: // RAR {acc, cc} = {cc, acc}; 4: // DAA, decimal adjust begin if((acc[3:0] > 9) || cac) acc = acc + 6; if((acc[7:4] > 9) || cc) {cc, acc} = {1'b0, acc} + 'h60; end 5: // CMA acc = ~acc; 6: // STC cc = 1; 7: // CMC cc = ~cc; endcase endtask 34 /* increment and decrement register pair */ task inx_dcx; case(ir[5:3]) 0: {regb, regc} = {regb, regc} + 1; 1: {regb, regc} = {regb, regc} - 1; 2: {regd, rege} = {regd, rege} + 1; 3: {regd, rege} = {regd, rege} - 1; 4: {regh, regl} = {regh, regl} + 1; 5: {regh, regl} = {regh, regl} - 1; 6: sp = sp + 1; 7: sp = sp - 1; endcase endtask /* load register pair immediate */ task lrpi; case(ir[5:4]) 0: adread({regb, regc}); 1: adread({regd, rege}); 2: adread({regh, regl}); 3: adread(sp); endcase endtask // INX B // DCX B // INX D // DCX D // INX H // DCX H // INX SP // DCX SP // LXI B // LXI D // LXI H // LXI SP 35 /* add into regh, regl pair */ task addhl; begin case(ir[5:4]) 0: {cc, regh, regl} = {1'b0, regh, regl} + {regb, regc}; // DAD B 1: {cc, regh, regl} = {1'b0, regh, regl} + {regd, rege}; // DAD D 2: {cc, regh, regl} = {1'b0, regh, regl} + {regh, regl}; // DAD H 3: {cc, regh, regl} = {1'b0, regh, regl} + sp; // DAD SP endcase end endtask 36