⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpu.v

📁 简单的一个8位RISC
💻 V
📖 第 1 页 / 共 2 页
字号:
assign k =     inst[7:0];assign fsel  = inst[4:0];assign d     = inst[5];assign b     = inst[7:5];// Bit Decoder.//// Simply take the 3-bit b field in the PIC instruction and create the// expanded 8-bit decoder field, which is used as a mask.//always @(b) begin   case (b) // synopsys parallel_case      3'b000: bdec = 8'b00000001;      3'b001: bdec = 8'b00000010;      3'b010: bdec = 8'b00000100;      3'b011: bdec = 8'b00001000;      3'b100: bdec = 8'b00010000;      3'b101: bdec = 8'b00100000;      3'b110: bdec = 8'b01000000;      3'b111: bdec = 8'b10000000;   endcaseendalways @(bdec or bdpol)   bd = (bdpol) ? ~bdec : bdec;// Instruction regsiter usually get the ROM data as its input, but// sometimes for branching, the skip signal must cause a NOP.//always @(posedge clk) begin   if (reset) begin      inst <= 12'h000;   end   else begin      if (skip == 1'b1) begin         inst <= 12'b000000000000; // FORCE NOP      end      else begin         inst <= pdata;      end   endend// SKIP signal.//// We want to insert the NOP instruction for the following conditions://    GOTO,CALL and RETLW instructions (All have inst[11:10] = 2'b10//    BTFSS instruction when aluz is HI  (//    BTFSC instruction when aluz is LO//always @(inst or aluz) begin   casex ({inst, aluz}) // synopsys parallel_case      13'b10??_????_????_?:    // A GOTO, CALL or RETLW instructions         skip = 1'b1;               13'b0110_????_????_1:    // BTFSC instruction and aluz == 1         skip = 1'b1;	      13'b0111_????_????_0:    // BTFSS instruction and aluz == 0         skip = 1'b1;            13'b0010_11??_????_1:    // DECFSZ instruction and aluz == 1         skip = 1'b1;	      13'b0011_11??_????_1:    // INCFSZ instruction and aluz == 1         skip = 1'b1;	      default:         skip = 1'b0;   endcaseend// 4:1 Data MUX into alua////always @(aluasel or w or sbus or k or bd) begin   case (aluasel) // synopsys parallel_case      2'b00: alua = w;      2'b01: alua = sbus;      2'b10: alua = k;      2'b11: alua = bd;   endcaseend// 4:1 Data MUX into alub////always @(alubsel or w or sbus or k) begin   case (alubsel) // synopsys parallel_case      2'b00: alub = w;      2'b01: alub = sbus;      2'b10: alub = k;      2'b11: alub = 8'b00000001;   endcaseend// W Registeralways @(posedge clk) begin   if (reset) begin      w <= 8'h00;   end   else begin      if (wwe) begin         w <= dbus;      end   end   end// ************ Writes to various Special Registers (fsel between 0 and 7)// INDF Register (Register #0)////    Not a real register.  This is the Indirect Addressing mode register.//    See the regfileaddr logic.// TMR0 Register (Register #1)////    Timer0 is currently only a free-running timer clocked by the main system clock.//always @(posedge clk) begin   if (reset) begin      tmr0 <= 8'h00;   end   else begin      // See if the status register is actually being written to      if (fwe & specialsel & (fileaddr[2:0] == TMR0_ADDRESS)) begin         // Yes, so just update the register from the dbus         tmr0 <= dbus;      end      else begin         if (~option[5]) begin            // OPTION[3]  -  Assigns prescaler to either WDT or TIMER0.  We don't implement WDT.            //               If this bit is 0, then use the prescaler.  If 1 then increment.            //            // Mask off the prescaler value based on desired divide ratio.            // Whenever this is zero, then that is our divided pulse.  Increment            // the final timer value when it's zero.            //            casex (option[3:0]) // synopsys parallel_case full_case               4'b1XXX: tmr0 <= tmr0 + 1;               4'b0000: if (~|(prescaler & 8'b00000001)) tmr0 <= tmr0 + 1;               4'b0001: if (~|(prescaler & 8'b00000011)) tmr0 <= tmr0 + 1;               4'b0010: if (~|(prescaler & 8'b00000111)) tmr0 <= tmr0 + 1;               4'b0011: if (~|(prescaler & 8'b00001111)) tmr0 <= tmr0 + 1;               4'b0100: if (~|(prescaler & 8'b00011111)) tmr0 <= tmr0 + 1;               4'b0101: if (~|(prescaler & 8'b00111111)) tmr0 <= tmr0 + 1;               4'b0110: if (~|(prescaler & 8'b01111111)) tmr0 <= tmr0 + 1;               4'b0111: if (~|(prescaler & 8'b11111111)) tmr0 <= tmr0 + 1;            endcase                     end      end   endend// The prescaler is always counting from 00 to FF whenever OPTION[5] is cleared (e.g. T0CS)always @(posedge clk) begin   if (reset) begin      prescaler <= 8'h00;   end   else begin      if (~option[5]) begin         prescaler <= prescaler + 1;      end   endend// PCL Register (Register #2)////    PC Lower 8 bits.  This is handled in the PC section below...// STATUS Register (Register #3)//parameter STATUS_RESET_VALUE = 8'h18;always @(posedge clk) begin   if (reset) begin      status <= STATUS_RESET_VALUE;   end   else begin      // See if the status register is actually being written to      if (fwe & specialsel & (fileaddr[2:0] == STATUS_ADDRESS)) begin         // Yes, so just update the register from the dbus         status <= dbus;      end      else begin         // Update status register on a bit-by-bit basis.         //         // For the carry and zero flags, each instruction has its own rule as         // to whether to update this flag or not.  The instruction decoder is         // providing us with an enable for C and Z.  Use this to decide whether         // to retain the existing value, or update with the new alu status output.         //         status <= {            status[7],			// BIT 7: Undefined.. (maybe use for debugging)            status[6],			// BIT 6: Program Page, HI bit            status[5],			// BIT 5: Program Page, LO bit            status[4],			// BIT 4: Time Out bit (not implemented at this time)            status[3],			// BIT 3: Power Down bit (not implemented at this time)            (zwe) ? aluz : status[2],	// BIT 2: Z            status[1],			// BIT 1: DC            (cwe) ? alucout : status[0]	// BIT 0: C         };      end   endend// FSR Register  (Register #4)//            always @(posedge clk) begin   if (reset) begin      fsr <= 8'h00;   end   else begin      // See if the status register is actually being written to      if (fwe & specialsel & (fileaddr[2:0] == FSR_ADDRESS)) begin         fsr <= dbus;      end   endend// OPTION Register//// The special OPTION instruction should move W into the OPTION register.//parameter OPTION_RESET_VALUE = 8'h3F;always @(posedge clk) begin   if (reset) begin      option <= OPTION_RESET_VALUE;   end   else begin      if (isoption)         option <= dbus;   end   end// PORTA Input Port   (Register #5)//// Register anything on the module's porta input on every single clock.//always @(posedge clk)   if (reset) porta <= 8'h00;   else       porta <= portain;// PORTB Output Port  (Register #6)always @(posedge clk) begin   if (reset) begin      portb <= 8'h00;   end   else begin      if (fwe & specialsel & (fileaddr[2:0] == PORTB_ADDRESS) & ~istris) begin         portb <= dbus;      end   end   end// Connect the output ports to the register output.always @(portb)   portbout = portb;   // PORTC Output Port  (Register #7)always @(posedge clk) begin   if (reset) begin      portc <= 8'h00;   end   else begin      if (fwe & specialsel & (fileaddr[2:0] == PORTC_ADDRESS) & ~istris) begin         portc <= dbus;      end   end   end// Connect the output ports to the register output.always @(portc)   portcout = portc; // TRIS Registersalways @(posedge clk) begin   if (reset) begin      trisa <= 8'hff; // Default is to tristate them   end   else begin      if (fwe & specialsel & (fileaddr[2:0] == PORTA_ADDRESS) & istris) begin         trisa <= dbus;      end   end   endalways @(posedge clk) begin   if (reset) begin      trisb <= 8'hff; // Default is to tristate them   end   else begin      if (fwe & specialsel & (fileaddr[2:0] == PORTB_ADDRESS) & istris) begin         trisb <= dbus;      end   end   endalways @(posedge clk) begin   if (reset) begin      trisc <= 8'hff; // Default is to tristate them   end   else begin      if (fwe & specialsel & (fileaddr[2:0] == PORTC_ADDRESS) & istris) begin         trisc <= dbus;      end   end   end  // ********** PC AND STACK *************************//// There are 4 ways to change the PC.  They are://    GOTO  101k_kkkk_kkkk//    CALL  1001_kkkk_kkkk//    RETLW 1000_kkkk_kkkk//    MOVF  0010_0010_0010  (e.g. a write to reg #2)//    MOVWF 0000_0010_0010  (write from W to reg #2)//// Remember that the skip instructions work by inserting// a NOP instruction or not into program stream and don't// change the PC.//// Implmenent PC//// Seperate the PC_IN input bus into PC from the sequential register so that we// can feed the PC_IN bus into the PRAM address input.always @(posedge clk)   if (reset) pc <= RESET_VECTOR;   else       pc <= pc_in;always @(inst or stacklevel or status or stack1 or stack2 or pc or dbus) begin   casex ({inst, stacklevel}) // synopsys parallel_case      14'b101?_????_????_??: pc_in = {status[6:5],       inst[8:0]};	// GOTO      14'b1001_????_????_??: pc_in = {status[6:5], 1'b0, inst[7:0]};	// CALL      14'b1000_????_????_00: pc_in = stack1;				// RETLW      14'b1000_????_????_01: pc_in = stack1;				// RETLW      14'b1000_????_????_10: pc_in = stack2;				// RETLW      14'b1000_????_????_11: pc_in = stack2;				// RETLW      14'b00?0_0010_0010_??: pc_in = {pc[10:8], dbus};		// MOVF or MOVWF where f=PC      default:         pc_in = pc + 1;   endcaseend// Implement STACK1 and STACK2 registers//// The Stack registers are only fed from the PC itself!//always @(posedge clk) begin   if (reset) begin      stack1 <= 9'h000;   end   else begin      // CALL instruction      if (inst[11:8] == 4'b1001) begin         case (stacklevel) // synopsys parallel_case            2'b00:               // No previous CALLs                begin                  stack1 <= pc;               end            2'b01:               // ONE previous CALL                begin                  stack2 <= pc;               end            2'b10:               // TWO previous CALLs -- This is illegal on the 16C5X!                begin                  $display ("Too many CALLs!!");               end            2'b11:                begin                  $display ("Too many CALLs!!");               end         endcase      end   endend// Write to stacklevel//// The stacklevel register keeps track of the current stack depth.  On this// puny processor, there are only 2 levels (you could fiddle with this and// increase the stack depth).  There are two stack registers, stack1 and stack2.// The stack1 register is used first (e.g. the first time a call is performed),// then stack2.  As CALLs are done, stacklevel increments.  Conversely, as// RETs are done, stacklevel goes down. always @(posedge clk) begin   if (reset == 1'b1) begin      stacklevel <= 2'b00;  // On reset, there should be no CALLs in progress   end   else begin      casex ({inst, stacklevel}) // synopsys parallel_case         // Call instructions         14'b1001_????_????_00: stacklevel <= 2'b01;  // Record 1st CALL         14'b1001_????_????_01: stacklevel <= 2'b10;  // Record 2nd CALL         14'b1001_????_????_10: stacklevel <= 2'b10;  // Already 2! Ignore         14'b1001_????_????_11: stacklevel <= 2'b00;  // {shouldn't happen}         // Return instructions         14'b1000_????_????_00: stacklevel <= 2'b00;  // {shouldn't happen}         14'b1000_????_????_01: stacklevel <= 2'b00;  // Go back to no CALL in progress         14'b1000_????_????_10: stacklevel <= 2'b01;  // Go back to 1 CALL in progress         14'b1000_????_????_11: stacklevel <= 2'b10;  // {shouldn't happen} sort of like, Go back to 2 calls in progress         default:            stacklevel <= stacklevel;      endcase   endend// *******  Debug Stuff  ******** ////// The following is NOT synthesizable.  This code simply allows you to see the ASCII name// for the instruction in the INST register while in a waveform viewer.//// synopsys translate_offreg [8*8-1:0] inst_string;always @(inst) begin   casex (inst)      12'b0000_0000_0000: inst_string = "NOP     ";      12'b0000_001X_XXXX: inst_string = "MOVWF   ";      12'b0000_0100_0000: inst_string = "CLRW    ";      12'b0000_011X_XXXX: inst_string = "CLRF    ";      12'b0000_10XX_XXXX: inst_string = "SUBWF   ";      12'b0000_11XX_XXXX: inst_string = "DECF    ";      12'b0001_00XX_XXXX: inst_string = "IORWF   ";      12'b0001_01XX_XXXX: inst_string = "ANDWF   ";      12'b0001_10XX_XXXX: inst_string = "XORWF   ";      12'b0001_11XX_XXXX: inst_string = "ADDWF   ";      12'b0010_00XX_XXXX: inst_string = "MOVF    ";      12'b0010_01XX_XXXX: inst_string = "COMF    ";      12'b0010_10XX_XXXX: inst_string = "INCF    ";      12'b0010_11XX_XXXX: inst_string = "DECFSZ  ";      12'b0011_00XX_XXXX: inst_string = "RRF     ";      12'b0011_01XX_XXXX: inst_string = "RLF     ";      12'b0011_10XX_XXXX: inst_string = "SWAPF   ";      12'b0011_11XX_XXXX: inst_string = "INCFSZ  ";      // *** Bit-Oriented File Register Operations      12'b0100_XXXX_XXXX: inst_string = "BCF     ";      12'b0101_XXXX_XXXX: inst_string = "BSF     ";      12'b0110_XXXX_XXXX: inst_string = "BTFSC   ";      12'b0111_XXXX_XXXX: inst_string = "BTFSS   ";      // *** Literal and Control Operations      12'b0000_0000_0010: inst_string = "OPTION  ";      12'b0000_0000_0011: inst_string = "SLEEP   ";      12'b0000_0000_0100: inst_string = "CLRWDT  ";      12'b0000_0000_0101: inst_string = "TRIS    ";      12'b0000_0000_0110: inst_string = "TRIS    ";      12'b0000_0000_0111: inst_string = "TRIS    ";      12'b1000_XXXX_XXXX: inst_string = "RETLW   ";      12'b1001_XXXX_XXXX: inst_string = "CALL    ";      12'b101X_XXXX_XXXX: inst_string = "GOTO    ";      12'b1100_XXXX_XXXX: inst_string = "MOVLW   ";      12'b1101_XXXX_XXXX: inst_string = "IORLW   ";      12'b1110_XXXX_XXXX: inst_string = "ANDLW   ";      12'b1111_XXXX_XXXX: inst_string = "XORLW   ";      default:            inst_string = "-XXXXXX-";   endcaseend   // synopsys translate_onendmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -