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