📄 risc16f84_clk2x.v
字号:
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 + -