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

📄 risc16f84_clk2x.v

📁 hrisc cpu
💻 V
📖 第 1 页 / 共 3 页
字号:
         or inst_btfsc
         or inst_btfss
         or inst_clrf
         or inst_addlw
         or inst_sublw
         or inst_andlw
         or inst_iorlw
         or inst_xorlw
         or inst_retlw
         or inst_clrw
         or inst_swapf
         or inst_addwf
         or inst_subwf
         or inst_andwf
         or inst_iorwf
         or inst_xorwf
         or inst_decf
         or inst_incf
         or inst_rlf
         or inst_rrf
         or inst_decfsz
         or inst_incfsz
         or inst_comf
         )
begin
  // 2-4-1-1. Set aluout register
          // Rotate left
  if      (inst_rlf) 
          aluout <= {aluinp1_reg[6:0],status_reg[0]};
          // Rotate right
  else if (inst_rrf) 
          aluout  <= {status_reg[0],aluinp1_reg[7:1]};
          // Swap nibbles
  else if (inst_swapf)
          aluout <= {aluinp1_reg[3:0],aluinp1_reg[7:4]};
          // Logical inversion
  else if (inst_comf)
          aluout  <= ~aluinp1_reg;
          // Logical AND, bit clear/bit test
  else if (   inst_andlw || inst_andwf || inst_bcf || inst_btfsc
           || inst_btfss) 
          aluout  <= (aluinp1_reg & aluinp2_reg);
          // Logical OR, bit set
  else if (inst_bsf || inst_iorlw || inst_iorwf)
          aluout  <= (aluinp1_reg | aluinp2_reg);
          // Logical XOR
  else if (inst_xorlw || inst_xorwf)
          aluout  <= (aluinp1_reg ^ aluinp2_reg);
          // Addition, Subtraction, Increment, Decrement
  else if (  inst_addlw || inst_addwf  || inst_sublw || inst_subwf
           || inst_decf || inst_decfsz || inst_incf  || inst_incfsz)
          aluout  <= add_node[7:0];
          // Pass through
  else aluout  <= aluinp1_reg;
end


// MAIN EFSM: description of register value changes in each clock cycle
always @(posedge clk_i)
begin
  // Assign reset (default) values of registers
  if (reset_i)
  begin
    status_reg[7:5] <= 3'b0;
    pclath_reg      <= 0;     // 0
    intcon_reg[7:1] <= 7'b0;
    aux_adr_lo_reg  <= 0;
    aux_adr_hi_reg  <= 0;
    ram_we_reg      <= 0;
    status_reg[4]   <= 1;     // /T0 = 1
    status_reg[3]   <= 1;     // /PD = 1
    stack_pnt_reg   <= 0;     // Reset stack pointer
  end  // End of reset assignments
  else if (~exec_stall_reg && clk_en_i) 
  begin   // Execution ceases during a stall cycle.
    if (state_reg == Q2_PP) // 2-3. Q2 cycle
    begin
      // 2-3-1. Read data-RAM and store values to alu-input regs
      // 2-3-1-1. Set aluinp1 register (source #1)
      if (   inst_movf   || inst_swapf || inst_addwf || inst_subwf
          || inst_andwf  || inst_iorwf || inst_xorwf || inst_decf
          || inst_incf   || inst_rlf   || inst_rrf   || inst_bcf
          || inst_bsf    || inst_btfsc || inst_btfss || inst_decfsz
          || inst_incfsz || inst_comf)

          aluinp1_reg <= ram_i_node;       // RAM/Special registers
      else
      if (   inst_movlw || inst_addlw || inst_sublw || inst_andlw
          || inst_iorlw || inst_xorlw || inst_retlw)
          aluinp1_reg <= inst_reg[7:0];    // Immediate value ("k")
      else
      if (   inst_clrf  || inst_clrw) aluinp1_reg <= 0; // 0
      else aluinp1_reg <= w_reg;                        // W register

      // 2-3-1-2. Set aluinp2 register (source #2)
      c_in <= 0; // Default to no carry in.
      if      (inst_decf || inst_decfsz) aluinp2_reg <= -1; // for decr.
      else if (inst_incf || inst_incfsz) aluinp2_reg <=  1; // for incr.
              // -1 * W register (for subtract)
      else if (inst_sublw || inst_subwf) 
      begin
        aluinp2_reg <= ~w_reg + 1; 
        c_in <= 1;  // Set c_in for subtract operations (makes C come out).
      end
            // operation of BCF: AND with inverted mask ("1..101..1")
            // mask for BCF: value of only one position is 0
      else if (inst_bcf) aluinp2_reg <= ~mask_node; 
            // operation of BSF: OR with mask_node ("0..010..0")
            // operation of FSC and FSS: AND with mask_node, compare to 0
      else if (inst_btfsc || inst_btfss || inst_bsf)
                                  aluinp2_reg <= mask_node;
      else aluinp2_reg <= w_reg; // W register

      // 2-3-1-3. Set stack pointer register (pop stack)
      if (inst_ret || inst_retlw || inst_retfie)
           stack_pnt_reg   <= stack_pnt_reg - 1; // cycles 3,2,1,0,7,6...

      // 2-4-1-3. Set data-SRAM write enable (hazard-free)
      // Set the write enables depending on the destination.
      // (These have been implemented as registers to avoid glitches?
      // It is not known to me (John Clayton) whether any glitches would
      // really occur.  It might be possible to generate these signals
      // using combinational logic only, without using registers!
      ram_we_reg <= (writeram_node && addr_sram);
      aux_we_reg <= (writeram_node && addr_aux_dat);
    end   // End of Q2 state
    
    //---------------------------------------------------------------------
    
    else if (state_reg == QINT_PP) // Interrupt execution (instead of Q4_PP)
    begin
        // PORT-B0 INT
        intcon_reg[1] <= 1;                     // set INTF
        intcon_reg[7] <= 0;                     // clear GIE
        stack_reg[stack_pnt_reg] <= old_pc_reg; // Push old PC
        stack_pnt_reg <= stack_pnt_reg + 1;     // increment stack pointer
        // The old PC is pushed, so that the pre-empted instruction can be
        // restarted later, when the retfie is executed.
    end

    //---------------------------------------------------------------------

    else if (state_reg == Q4_PP)   // Execution & writing of results.
    begin

      if (inst_call)
      begin
        stack_reg[stack_pnt_reg] <= pc_reg;     // Push current PC
        stack_pnt_reg <= stack_pnt_reg + 1;     // increment stack pointer
      end

      if (inst_retfie) // "return from interrupt" instruction
      begin
        intcon_reg[7] <= 1;                     // Set GIE
      end

      // 2-4-1-2. Set C flag and DC flag
      if (inst_addlw || inst_addwf || inst_sublw || inst_subwf)
      begin
        status_reg[1]   <= addlow_node[4];         // DC flag
        status_reg[0]   <= add_node[8];            // C flag
      end
      else if (inst_rlf) status_reg[0] <= aluinp1_reg[7];  // C flag
      else if (inst_rrf) status_reg[0] <= aluinp1_reg[0];  // C flag

      // 2-5-2. Store calculation result into destination, 
      // 2-5-2-1. Set W register

      if (writew_node) w_reg   <= aluout;    // write W reg

      // 2-5-2-2. Set data RAM/special registers,
      if (writeram_node)
      begin
        if (addr_stat)
        begin
          status_reg[7:5] <= aluout[7:5];      // write IRP,RP1,RP0
          // status(4),status(3)...unwritable, see below (/PD,/T0 part)
          status_reg[1:0] <= aluout[1:0];      // write DC,C
        end
        if (addr_fsr)         fsr_reg <= aluout;       // write FSR
        if (addr_pclath)   pclath_reg <= aluout[4:0];  // write PCLATH
        if (addr_intcon) intcon_reg <= aluout;         // write INTCON
        if (addr_aux_adr_lo) aux_adr_lo_reg <= aluout; // write AUX low
        if (addr_aux_adr_hi) aux_adr_hi_reg <= aluout; // write AUX high
      end

      // 2-5-2-3. Set/clear Z flag.
      if (addr_stat) status_reg[2] <= aluout[2]; // (dest. is Z flag)
      else if (   inst_addlw || inst_addwf || inst_andlw || inst_andwf
               || inst_clrf  || inst_clrw  || inst_comf  || inst_decf
               || inst_incf  || inst_movf  || inst_sublw || inst_subwf
               || inst_xorlw || inst_xorwf || inst_iorlw || inst_iorwf )
              status_reg[2] <= aluout_zero_node; // Z=1 if result == 0

      // 2-5-3. Clear RAM write enables (hazard-free)
      ram_we_reg <= 0;
      aux_we_reg <= 0;

    end    // End of Q4 state
  end // End of "if (~exec_stall_reg)"    
end  // End of process


// Calculation of next processor state.
// (Not including reset conditions, which are covered by the clocked logic,
//  which also includes a "global clock enable."
always @(
            state_reg
         or inst_sleep
         or inte_sync_reg
         or exec_stall_reg
         or int_condition
         )
begin
  case (state_reg)
  Q2_PP     : if (int_condition) next_state_node <= QINT_PP;
              else next_state_node <= Q4_PP;
  Q4_PP     : if (~exec_stall_reg && inst_sleep) next_state_node <= QSLEEP_PP;
              else next_state_node <= Q2_PP;
  QINT_PP   : next_state_node <= Q2_PP;
  QSLEEP_PP : if (inte_sync_reg) next_state_node <= Q2_PP;
              else next_state_node <= QSLEEP_PP;
              // Default condition provided for convention and completeness
              // only.  Logically, all of the conditions are already covered.
  default   : next_state_node <= Q2_PP;
  endcase
end


// Clocked state transitions, based upon dataflow (non-clocked logic) in
// the previous always block.
always @(posedge clk_i)
begin
  if (reset_i) state_reg <= Q2_PP;
  else if (clk_en_i) state_reg <= next_state_node;
end  // End of process


// Detect external interrupt requests
// You can code multiple interrupts if you wish, or use the single interrupt
// provided and simply have the interrupt service routine (ISR) check to find
// out the source of the interrupt, by or-ing together all of the interrupt
// sources and providing a readable register of their values at the time
// the interrupt occurred.
//
// When an interrupt is recognized by the processor, this is signified by
// entering "QINT_PP," which is treated like an executable instruction.
// The interrupt instruction can only be executed when not in a stall condition.
// It simply "pre-empts" the instruction that would have been executed during
// that cycle.  Then, when retfie is executed, the pre-empted instruction is
// re-started (the stall cycle of the retfie is when the address of the 
// instruction being re-started is fetched.)
//
// I was unable to obtain correct operation for capturing the negative edge,
// so I am discarding it.  If one really needs to generate an interrupt on the
// falling edge, just use an inverted version of the signal (the inversion is
// often "free" inside of an FPGA anyhow.)
//
// Upon further testing, I discovered that even the rising edge "trigger" was not
// really truly an edge detection, it was more like a "set-reset" flip flop
// type of behavior.  Rather than mess around with it any more, I am implementing
// a clocked "poor man's rising edge detector."
// Capture the rising edge of the interrupt input...  This part is self clearing.
// It also means that the interrupt must last longer than one clock cycle in
// order to be properly recognized.  (It is "pseudo edge triggered", not a true
// rising edge trigger.)
// When the interrupt is recognized, inte_sync_reg is cleared.


always @(posedge clk_i)
begin
  if (clk_en_i) intrise_reg <= int0_i;
end // process
assign intrise = (int0_i && ~intrise_reg);

//  The inte_sync_reg signal is used for waking up from SLEEP.
//  (this flip flop is also a synchronizer to minimize the
//   possibility of metastability due to changes at the input
//   occurring at the same time as the processor clock edge...)
//  It might be possible to eliminate this step, and issue the interrupt
//  directly without this intermediate synchronizer flip-flop.
always @(posedge clk_i)
begin
  if (reset_i || (state_reg == QINT_PP)) inte_sync_reg <= 0;
  else if (clk_en_i && intrise && intcon_reg[4]) inte_sync_reg <= 1;
end

// Issue an interrupt when the interrupt is present.
// Also, do not issue an interrupt when there is a stall cycle coming!
assign int_condition = (inte_sync_reg && ~exec_stall_reg && intcon_reg[7]);
                               // Interrupt must be pending
                               // Next processor cycle must not be a stall
                               // GIE bit must be set to issue interrupt

// Circuit's output signals
assign prog_adr_o = pc_reg;        // program ROM address
assign ram_adr_o  = ram_adr_node;  // data RAM address
assign ram_dat_o  = aluout;        // data RAM write data
assign ram_we_o   = ram_we_reg;    // data RAM write enable

assign aux_adr_o  = {aux_adr_hi_reg,aux_adr_lo_reg};
assign aux_dat_io = (aux_we_reg && clk_en_i)?aluout:{8{1'bZ}};
assign aux_we_o   = aux_we_reg;

endmodule


//`undef STATEBIT_SIZE

⌨️ 快捷键说明

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