380 likes | 576 Views
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
E N D
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.
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
S0, S1 (Output)Data Bus Status. Encoded status of the bus cycle:S1 S00 0 HALT0 1 WRITE1 0 READ1 1 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.
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.
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 PriorityRST 6.5RST 5.5 Lowest PriorityThe priority of these interrupts is ordered as shown above. These interrupts have a higher priority than the INTR.
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 2416 RST 5.5 2C16RST 6.5 3416RST 7.5 3C16 RESET IN (Input)Reset sets the Program Counter to zero and resets the Interrupt Enable and HLDA flip flops.
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
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] ad, a; tri1 read, write, iomout; reg trap, rst7p5, rst6p5, rst5p5, intr, ready, nreset, hold, pclock;
//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
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;
reg[15:0] pc, // program counter sp, // stack pointer addr; // address output reg[8:0] intmask; // interrupt mask and status reg[7:0] acc, // accumulator regb, // general regc, // general regd, // general rege, // general regh, // general regl, // general ir, // instruction data; // data output reg aleff, // address latch enable s0ff, // status line 0 s1ff, // status line 1 hldaff, // hold acknowledge holdff, // internal hold
intaff, // interrupt acknowledge trapff, // trap interrupt request trapi, // trap execution for RIM instruction (RIM:read interrupt mask) inte, // previous state of interrupt enable flag int, // interrupt acknowledge in progress validint, // interrupt pending haltff, // halt request resetff, // reset output clockff, // clock output sodff, // serial output data read, // read request signal write, // write request signal iomff, // i/o memory select acontrol, // address output control dcontrol, // data output control s, // data source control cs, // sign condition code cz, // zero condition code cac, // aux carry condition code cp, // parity condition code cc; // carry condition code
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
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 // move data at port to Accumulator (A) (port) // two byte instruction, first byte is OPCODE //second byte is port address OUT port //move data from A to port (port) (A) For examples IN 5 OUT 1
LDA addr //load accumulator direct (A) ((byte 3) (byte 2)) STA addr //store accumulator direct ((byte 3)(byte 2)) (A) example: LDA First // First is a 16-bit address STA First 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 //move from memory specified by HL (r) ((H)(L)) //to a register r example MOV B, M
MOV M, r //store r in memory LDAX rp //load accumulator indirect (A) ((rp)) STAX rp //store accumulator indirect ((rp)) (A) MVI r, data //move immediate (r) (byte 2) LXI rp, data 16 //load register pair immediate (rl) (byte 2) (rh) (byte 3) MVI M, data //move to memory immediate ((H)(L)) (byte 2)
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
/* 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
/* 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
/* 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
/* 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
/* 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
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
@(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 /* 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;
/* 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
Logic and Arithmetic operations CMA // complement the accumulator (A) (A) CMC // complement the carry flag (CY) (CY) STC // set the carry flag ANI data // AND immediate, A and with byte 2 ANA r // A and with register r ANA M // A and with memory ORI // OR immediate, A or with byte 2 ORA r // A or with register r ORA M // A or with memory XRI data // Exclusive_OR immediate XRA r // A xor with register r XRA M // A xor with memory CPI data // compare immediate CMP r // compare register CMP M // compare memory
RLC rotate accumulator left (CY) A7; A0 A7; An+1 An RRC rotate accumulator right (CY) A0; A7 A0; An An+1 RAL rotate left through carry RAR 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
SBI data subtract immediate with borrow INR r increment register INR M increment memory DCR r decrement register DCR M decrement memory INX rp increment register pair DCX rp decrement register pair DAD rp add register pair to H and L DAA decimal adjust accumulator
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 /* 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
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
/* 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};
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
/* increment and decrement register pair */ task inx_dcx; case(ir[5:3]) 0: {regb, regc} = {regb, regc} + 1; // INX B 1: {regb, regc} = {regb, regc} - 1; // DCX B 2: {regd, rege} = {regd, rege} + 1; // INX D 3: {regd, rege} = {regd, rege} - 1; // DCX D 4: {regh, regl} = {regh, regl} + 1; // INX H 5: {regh, regl} = {regh, regl} - 1; // DCX H 6: sp = sp + 1; // INX SP 7: sp = sp - 1; // DCX SP endcase endtask /* load register pair immediate */ task lrpi; case(ir[5:4]) 0: adread({regb, regc}); // LXI B 1: adread({regd, rege}); // LXI D 2: adread({regh, regl}); // LXI H 3: adread(sp); // LXI SP endcase endtask
/* 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