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

📄 risc16f84_clk2x.v

📁 hrisc cpu
💻 V
📖 第 1 页 / 共 3 页
字号:
wire addr_stat;
wire addr_fsr;
wire addr_pclath;
wire addr_intcon;
wire addr_aux_adr_lo;
wire addr_aux_adr_hi;
wire addr_aux_dat;
wire addr_sram;

     // Other output registers (for removing hazards)
reg  ram_we_reg;          // data-sram write strobe
reg  aux_we_reg;          // AUX write strobe


     // Signals used in "main_efsm" procedure
     // (Intermediate nodes used for resource sharing.)
wire [7:0]  ram_i_node;    // result of reading RAM/Special registers
wire [7:0]  mask_node;     // bit mask for logical operations
wire [8:0]  add_node;      // result of 8bit addition
wire [4:0]  addlow_node;   // result of low-4bit addition
wire temp;                // Placeholder wire
wire dtemp;               // Placeholder wire
wire aluout_zero_node;    // H if ALUOUT = 0

reg  [12:0] next_pc_node;  // value of next PC
reg  [7:0] aluout;        // result of calculation
reg  writew_node;         // H if destination is W register
reg  writeram_node;       // H if destination is RAM/Special registers

//--------------------------------------------------------------------------
// Instantiations
//--------------------------------------------------------------------------


//--------------------------------------------------------------------------
// Functions & Tasks
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
// Module code
//--------------------------------------------------------------------------

// This represents the instruction fetch from program memory.
// inst_reg[13:0] stores the instruction.  This happens at the end of Q4.
// So the memory access time is one processor cycle (2 clocks!) minus
// the setup-time of this register, and minus the delay to drive the 
// address out onto the prog_adr_o bus.
always @(posedge clk_i)
begin
  if (reset_i) inst_reg <= 0;
  else if (clk_en_i && (state_reg == Q4_PP)) inst_reg <= prog_dat_i;
end

// NOTE: There is an extra "15th" bit of inst_reg, which represents an
// interrupt execution cycle.  This is included in inst_reg so that when
// an interrupt instruction is executing, it effectively "pre-empts" the
// other instructions.
// The fifteenth bit, inst_reg[14], is set by the interrupt logic.

// Decode OPcode    (see pp.54 of PIC16F84 data sheet)
// only 1 signal of the following signals will be '1'
assign inst_call    = (inst_reg[13:11] ==  3'b100           );
assign inst_goto    = (inst_reg[13:11] ==  3'b101           );
assign inst_bcf     = (inst_reg[13:10] ==  4'b0100          );
assign inst_bsf     = (inst_reg[13:10] ==  4'b0101          );
assign inst_btfsc   = (inst_reg[13:10] ==  4'b0110          );
assign inst_btfss   = (inst_reg[13:10] ==  4'b0111          );
assign inst_movlw   = (inst_reg[13:10] ==  4'b1100          );
assign inst_retlw   = (inst_reg[13:10] ==  4'b1101          );
assign inst_sublw   = (inst_reg[13:9]  ==  5'b11110         );
assign inst_addlw   = (inst_reg[13:9]  ==  5'b11111         );
assign inst_iorlw   = (inst_reg[13:8]  ==  6'b111000        );
assign inst_andlw   = (inst_reg[13:8]  ==  6'b111001        );
assign inst_xorlw   = (inst_reg[13:8]  ==  6'b111010        );
assign inst_subwf   = (inst_reg[13:8]  ==  6'b000010        );
assign inst_decf    = (inst_reg[13:8]  ==  6'b000011        );
assign inst_iorwf   = (inst_reg[13:8]  ==  6'b000100        );
assign inst_andwf   = (inst_reg[13:8]  ==  6'b000101        );
assign inst_xorwf   = (inst_reg[13:8]  ==  6'b000110        );
assign inst_addwf   = (inst_reg[13:8]  ==  6'b000111        );
assign inst_movf    = (inst_reg[13:8]  ==  6'b001000        );
assign inst_comf    = (inst_reg[13:8]  ==  6'b001001        );
assign inst_incf    = (inst_reg[13:8]  ==  6'b001010        );
assign inst_decfsz  = (inst_reg[13:8]  ==  6'b001011        );
assign inst_rrf     = (inst_reg[13:8]  ==  6'b001100        );
assign inst_rlf     = (inst_reg[13:8]  ==  6'b001101        );
assign inst_swapf   = (inst_reg[13:8]  ==  6'b001110        );
assign inst_incfsz  = (inst_reg[13:8]  ==  6'b001111        );
assign inst_movwf   = (inst_reg[13:7]  ==  7'b0000001       );
assign inst_clrw    = (inst_reg[13:7]  ==  7'b0000010       );
assign inst_clrf    = (inst_reg[13:7]  ==  7'b0000011       );
assign inst_ret     = (inst_reg[13:0]  == 14'b00000000001000);
assign inst_retfie  = (inst_reg[13:0]  == 14'b00000000001001);
assign inst_sleep   = (inst_reg[13:0]  == 14'b00000001100011);


// Calculate RAM access address (see pp.19 of PIC16F84 data sheet)

    // if "d"=0, indirect addressing is used, so RAM address is BANK+FSR
    // otherwise, RAM address is BANK+"d"
    // (see pp.19 of PIC16F84 data sheet)
assign ram_adr_node = (inst_reg[6:0]==0)?{status_reg[7],fsr_reg[7:0]}:
                               {status_reg[6:5],inst_reg[6:0]};

    // check if this is an access to external RAM or not
assign addr_sram   = (ram_adr_node[6:0] > 7'b0001011); //0CH-7FH,8CH-FFH

    // check if this is an access to special register or not
    // only 1 signal of the following signals will be '1'
assign addr_pcl     = (ram_adr_node[6:0] ==  7'b0000010);    // 02H, 82H
assign addr_stat    = (ram_adr_node[6:0] ==  7'b0000011);    // 03H, 83H
assign addr_fsr     = (ram_adr_node[6:0] ==  7'b0000100);    // 04H, 84H
assign addr_aux_dat = (ram_adr_node[7:0] == 8'b00001000);    // 08H
assign addr_pclath  = (ram_adr_node[6:0] ==  7'b0001010);    // 0AH, 8AH
assign addr_intcon  = (ram_adr_node[6:0] ==  7'b0001011);    // 0BH, 8BH
assign addr_aux_adr_lo = (ram_adr_node[7:0] == 8'b00000101); // 05H
assign addr_aux_adr_hi = (ram_adr_node[7:0] == 8'b00000110); // 06H

// construct bit-mask for logical operations and bit tests
assign mask_node = 1 << inst_reg[9:7];

// Create the exec_stall signal, based on the contents of the currently
// executing instruction (inst_reg).  next_exec_stall reflects the state
// to assign to exec_stall following the conclusion of the next Q4 state.
// All of these instructions cause an execution stall in the next cycle
// because they modify the program counter, and a new value is presented
// for fetching during the stall cycle, during which time no instruction
// should be executed.
//
// The conditional instructions are given along with their conditions for
// execution.  If the conditions are not met, there is no stall and nothing
// to execute.
assign next_exec_stall = (
                             inst_goto
                          || inst_call
                          || inst_ret
                          || inst_retlw
                          || inst_retfie
                          || (
                              (inst_btfsc || inst_decfsz || inst_incfsz) 
                              && aluout_zero_node
                              )
                          || (inst_btfss && ~aluout_zero_node)
                          || (addr_pcl && writeram_node)
                          );
always @(posedge clk_i)
begin
  if (reset_i) exec_stall_reg <= 0;
  else if (clk_en_i && (state_reg == QINT_PP)) exec_stall_reg <= 1;
  else if (clk_en_i && (state_reg == Q4_PP))
    exec_stall_reg <= (next_exec_stall && ~exec_stall_reg);
    // exec stall should never be generated during a stall cycle, because
    // a stall cycle doesn't execute anything...
end

assign stack_top = stack_reg[stack_pnt_reg];
// Formulate the next pc_reg value (the program counter.)
// During stall cycles, the pc is simply incremented...
always @(
            pc_reg
         or pclath_reg
         or aluout
         or stack_pnt_reg
         or stack_top
         or inst_ret
         or inst_retlw
         or inst_retfie
         or inst_goto
         or inst_call
         or inst_reg
         or writeram_node
         or addr_pcl
         or exec_stall_reg
         )
begin
  if (~exec_stall_reg &&(inst_ret || inst_retlw || inst_retfie))
    next_pc_node <= stack_top;
  else if (~exec_stall_reg &&(inst_goto || inst_call))
    next_pc_node <= {pclath_reg[4:3],inst_reg[10:0]};
  else if (~exec_stall_reg && (writeram_node && addr_pcl))
    // PCL is data-destination, but update the entire PC.
    next_pc_node <= {pclath_reg[4:0],aluout};
  else
    next_pc_node <= pc_reg + 1;
end

// Set the program counter
// If the sleep instruction is executing, then the PC is not allowed to be
// updated, since the processor will "freeze" and the instruction being fetched
// during the sleep instruction must be executed upon wakeup interrupt.
// Obviously, if the PC were to change at the end of the sleep instruction, then
// a different (incorrect) address would be fetched during the sleep time.
always @(posedge clk_i)
begin
  if (reset_i) begin
    pc_reg <= 0;
    old_pc_reg <= 0;
  end
  else if (clk_en_i && (state_reg == QINT_PP))
  begin
    old_pc_reg <= pc_reg;
    pc_reg <= 4;
  end
  else if (clk_en_i && ~inst_sleep && (state_reg == Q4_PP))
  begin
    old_pc_reg <= pc_reg;
    pc_reg <= next_pc_node;
  end
end

// 1. Intermediate nodes for resource sharing

// Tri-state drivers instead of a huge selector...  It produces smaller
// results, and runs faster.
assign ram_i_node = (addr_sram)       ?ram_dat_i:8'bZ;
assign ram_i_node = (addr_pcl)        ?pc_reg[7:0]:8'bZ;
assign ram_i_node = (addr_stat)       ?status_reg:8'bZ;
assign ram_i_node = (addr_fsr)        ?fsr_reg:8'bZ;
assign ram_i_node = (addr_aux_dat)    ?aux_dat_io:8'bZ;
assign ram_i_node = (addr_pclath)     ?{3'b0,pclath_reg}:8'bZ;
assign ram_i_node = (addr_intcon)     ?intcon_reg:8'bZ;
assign ram_i_node = (addr_aux_adr_lo) ?aux_adr_lo_reg:8'bZ;
assign ram_i_node = (addr_aux_adr_hi) ?aux_adr_hi_reg:8'bZ;

// 1-3. Adder (ALU)
// full 8bit-addition, with carry in/out.
// Note that "temp" and "dtemp" are intended to be thrown away.
// Also, addlow_node[3:0] are thrown away.
// Even though they are assigned, they should never be used.
assign {add_node,temp}     =    {1'b0,aluinp1_reg,1'b1} 
                              + {1'b0,aluinp2_reg,c_in};
// lower 4bit-addition
assign {addlow_node,dtemp} =    {1'b0,aluinp1_reg[3:0],1'b1} 
                              + {1'b0,aluinp2_reg[3:0],c_in};

// 1-4. Test if aluout = 0
assign aluout_zero_node = (aluout == 0)?1:0;

// 1-5. Determine destination
always @(
            inst_reg
         or inst_movwf
         or inst_bcf
         or inst_bsf
         or inst_clrf
         or inst_movlw
         or inst_addlw
         or inst_sublw
         or inst_andlw
         or inst_iorlw
         or inst_xorlw
         or inst_retlw
         or inst_clrw
         or inst_movf
         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
  if (inst_movwf || inst_bcf || inst_bsf || inst_clrf)
  begin
    writew_node     <= 0;
    writeram_node   <= 1;
  end
  else if (   inst_movlw || inst_addlw || inst_sublw || inst_andlw 
           || inst_iorlw || inst_xorlw || inst_retlw || inst_clrw)
  begin
    writew_node     <= 1;
    writeram_node   <= 0;
  end
  else if (   inst_movf   || inst_swapf || inst_addwf || inst_subwf
           || inst_andwf  || inst_iorwf || inst_xorwf || inst_decf 
           || inst_incf   || inst_rlf   || inst_rrf   || inst_decfsz 
           || inst_incfsz || inst_comf)
  begin
    writew_node     <= ~inst_reg[7];  // ("d" field of fetched instruction)
    writeram_node   <=  inst_reg[7];  // ("d" field of fetched instruction)
  end
  else
  begin
    writew_node     <= 0;
    writeram_node   <= 0;
  end
end // End of determine destination logic




// 2-4-1. Calculation and store result into alu-output register

always @(
            add_node
         or aluinp1_reg
         or aluinp2_reg
         or status_reg
         or inst_reg
         or inst_movwf
         or inst_bcf
         or inst_bsf

⌨️ 快捷键说明

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