Line 148... |
Line 148... |
// fix of 03/05/02. The fix of 03/05/02 correctly generated the
|
// fix of 03/05/02. The fix of 03/05/02 correctly generated the
|
// C bit for subtraction of zero, but unfortunately it introduced
|
// C bit for subtraction of zero, but unfortunately it introduced
|
// an error such that all subtraction results were off by 1.
|
// an error such that all subtraction results were off by 1.
|
// Obviously, this was unacceptable, and I think it has been fixed
|
// Obviously, this was unacceptable, and I think it has been fixed
|
// by the new signals "c_subtract_zero" and "c_dig_subtract_zero"
|
// by the new signals "c_subtract_zero" and "c_dig_subtract_zero"
|
// Update: 10/24/05 Added code patches to fix interrupt bug and status flag updates
|
//
|
// when using literal value of 0x03. These bugs were reported by
|
// Update: 23 june 2014 (Stanislav Corboot)
|
// an opencores.org user. Added three "disable_status_x" signals.
|
//
|
// Modified file still needs to be tested.
|
// - Bug fixed: interrupt handler executed one and the same
|
// Update: 06/29/13 This project is now CC-BY licensed. See risc16f84_license.txt
|
// instruction twice - before interruption and after it.
|
// for details.
|
// - Bug fixed: incorrect behavior of the zero flag after LITERAL
|
|
// instructions (xxxLW) if operand was equal 0x03 and if result
|
|
// equal zero.
|
|
// Example:
|
|
// movlw 0x03
|
|
// xorlw 0x03 -> WREG=0x00, ZF=0 - ERROR!
|
|
// or
|
|
// movlw 0xFD
|
|
// addlw 0x03 -> WREG=0x00, ZF=0 - ERROR!
|
|
// or
|
|
// movlw 0x00
|
|
// andlw 0x03 -> WREG=0x00, ZF=0 - ERROR!
|
|
// etc.
|
//
|
//
|
// Description
|
// Description
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
// This logic module implements a small RISC microcontroller, with functions
|
// This logic module implements a small RISC microcontroller, with functions
|
// and instruction set very similar to those of the Microchip 16F84 chip.
|
// and instruction set very similar to those of the Microchip 16F84 chip.
|
Line 346... |
Line 358... |
reg writeram_node; // H if destination is RAM/Special registers
|
reg writeram_node; // H if destination is RAM/Special registers
|
reg c_subtract_zero; // High for special case of C bit, when subtracting zero
|
reg c_subtract_zero; // High for special case of C bit, when subtracting zero
|
reg c_dig_subtract_zero; // High for special case of C bit, when subtracting zero
|
reg c_dig_subtract_zero; // High for special case of C bit, when subtracting zero
|
|
|
wire next_exec_stall;
|
wire next_exec_stall;
|
// Three signals used to disable status flag updates. Fixes bug when literal 0x03 is used.
|
|
wire disable_status_z;
|
|
wire disable_status_c;
|
|
wire disable_status_dc;
|
|
|
|
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
// Instantiations
|
// Instantiations
|
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
|
|
Line 443... |
Line 451... |
assign addr_aux_adr_hi = (ram_adr_node[7:0] == 8'b00000110); // 06H
|
assign addr_aux_adr_hi = (ram_adr_node[7:0] == 8'b00000110); // 06H
|
|
|
// construct bit-mask for logical operations and bit tests
|
// construct bit-mask for logical operations and bit tests
|
assign mask_node = 1 << inst_reg[9:7];
|
assign mask_node = 1 << inst_reg[9:7];
|
|
|
// disable write access for status flags
|
|
assign disable_status_z = (inst_addwf || inst_andwf || inst_clrf ||
|
|
inst_clrw || inst_comf || inst_decf ||
|
|
inst_incf || inst_iorwf || inst_movf ||
|
|
inst_subwf || inst_xorwf || inst_addlw ||
|
|
inst_andlw || inst_iorlw || inst_iorlw ||
|
|
inst_sublw || inst_xorlw) ? 1:0;
|
|
assign disable_status_c = (inst_addwf || inst_subwf || inst_rlf ||
|
|
inst_rrf || inst_addlw || inst_sublw ) ? 1:0;
|
|
assign disable_status_dc = (inst_addwf || inst_subwf || inst_addlw ||
|
|
inst_sublw ) ? 1:0;
|
|
|
|
|
|
// Create the exec_stall signal, based on the contents of the currently
|
// Create the exec_stall signal, based on the contents of the currently
|
// executing instruction (inst_reg). next_exec_stall reflects the state
|
// executing instruction (inst_reg). next_exec_stall reflects the state
|
// to assign to exec_stall following the conclusion of the next Q4 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
|
// All of these instructions cause an execution stall in the next cycle
|
// because they modify the program counter, and a new value is presented
|
// because they modify the program counter, and a new value is presented
|
Line 721... |
Line 716... |
end // End of reset assignments
|
end // End of reset assignments
|
else if (~exec_stall_reg && clk_en_i)
|
else if (~exec_stall_reg && clk_en_i)
|
begin // Execution ceases during a stall cycle.
|
begin // Execution ceases during a stall cycle.
|
if (state_reg == Q2_PP) // 2-3. Q2 cycle
|
if (state_reg == Q2_PP) // 2-3. Q2 cycle
|
begin
|
begin
|
|
if( ~int_condition ) // Bug fixed
|
|
begin
|
// 2-3-1. Read data-RAM and store values to alu-input regs
|
// 2-3-1. Read data-RAM and store values to alu-input regs
|
// 2-3-1-1. Set aluinp1 register (source #1)
|
// 2-3-1-1. Set aluinp1 register (source #1)
|
if ( inst_movf || inst_swapf || inst_addwf || inst_subwf
|
if ( inst_movf || inst_swapf || inst_addwf || inst_subwf
|
|| inst_andwf || inst_iorwf || inst_xorwf || inst_decf
|
|| inst_andwf || inst_iorwf || inst_xorwf || inst_decf
|
|| inst_incf || inst_rlf || inst_rrf || inst_bcf
|
|| inst_incf || inst_rlf || inst_rrf || inst_bcf
|
Line 771... |
Line 768... |
// It is not known to me (John Clayton) whether any glitches would
|
// It is not known to me (John Clayton) whether any glitches would
|
// really occur. It might be possible to generate these signals
|
// really occur. It might be possible to generate these signals
|
// using combinational logic only, without using registers!
|
// using combinational logic only, without using registers!
|
ram_we_reg <= (writeram_node && addr_sram);
|
ram_we_reg <= (writeram_node && addr_sram);
|
aux_we_reg <= (writeram_node && addr_aux_dat);
|
aux_we_reg <= (writeram_node && addr_aux_dat);
|
|
end // Bug fixed
|
end // End of Q2 state
|
end // End of Q2 state
|
|
|
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
|
|
else if (state_reg == QINT_PP) // Interrupt execution (instead of Q4_PP)
|
else if (state_reg == QINT_PP) // Interrupt execution (instead of Q4_PP)
|
Line 821... |
Line 819... |
// 2-5-2. Store calculation result into destination,
|
// 2-5-2. Store calculation result into destination,
|
// 2-5-2-1. Set W register
|
// 2-5-2-1. Set W register
|
|
|
if (writew_node) w_reg <= aluout; // write W reg
|
if (writew_node) w_reg <= aluout; // write W reg
|
|
|
|
|
// 2-5-2-2. Set data RAM/special registers,
|
// 2-5-2-2. Set data RAM/special registers,
|
if (writeram_node)
|
if (writeram_node)
|
begin
|
begin
|
if (addr_stat)
|
if (addr_stat)
|
begin
|
begin
|
status_reg[7:5] <= aluout[7:5]; // write IRP,RP1,RP0
|
status_reg[7:5] <= aluout[7:5]; // write IRP,RP1,RP0
|
// status(4),status(3)...unwritable, see below (/PD,/T0 part)
|
// status(4),status(3)...unwritable, see below (/PD,/T0 part)
|
if( ~disable_status_c ) status_reg[0] <= aluout[0]; // write C
|
status_reg[1:0] <= aluout[1:0]; // write DC,C
|
if( ~disable_status_dc ) status_reg[1] <= aluout[1]; // write DC
|
|
end
|
end
|
if (addr_fsr) fsr_reg <= aluout; // write FSR
|
if (addr_fsr) fsr_reg <= aluout; // write FSR
|
if (addr_pclath) pclath_reg <= aluout[4:0]; // write PCLATH
|
if (addr_pclath) pclath_reg <= aluout[4:0]; // write PCLATH
|
if (addr_intcon) intcon_reg <= aluout; // write INTCON
|
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_lo) aux_adr_lo_reg <= aluout; // write AUX low
|
if (addr_aux_adr_hi) aux_adr_hi_reg <= aluout; // write AUX high
|
if (addr_aux_adr_hi) aux_adr_hi_reg <= aluout; // write AUX high
|
end
|
end
|
|
|
// 2-5-2-3. Set/clear Z flag.
|
// 2-5-2-3. Set/clear Z flag.
|
if (addr_stat && ~disable_status_z) status_reg[2] <= aluout[2];
|
if (addr_stat && !writew_node) status_reg[2] <= aluout[2]; // (dest. is Z flag) // Bug fixed
|
else if ( inst_addlw || inst_addwf || inst_andlw || inst_andwf
|
else if ( inst_addlw || inst_addwf || inst_andlw || inst_andwf
|
|| inst_clrf || inst_clrw || inst_comf || inst_decf
|
|| inst_clrf || inst_clrw || inst_comf || inst_decf
|
|| inst_incf || inst_movf || inst_sublw || inst_subwf
|
|| inst_incf || inst_movf || inst_sublw || inst_subwf
|
|| inst_xorlw || inst_xorwf || inst_iorlw || inst_iorwf )
|
|| inst_xorlw || inst_xorwf || inst_iorlw || inst_iorwf )
|
status_reg[2] <= aluout_zero_node; // Z=1 if result == 0
|
status_reg[2] <= aluout_zero_node; // Z=1 if result == 0
|
Line 942... |
Line 938... |
else if (clk_en_i && intrise && intcon_reg[4]) inte_sync_reg <= 1;
|
else if (clk_en_i && intrise && intcon_reg[4]) inte_sync_reg <= 1;
|
end
|
end
|
|
|
// Issue an interrupt when the interrupt is present.
|
// Issue an interrupt when the interrupt is present.
|
// Also, do not issue an interrupt when there is a stall cycle coming!
|
// Also, do not issue an interrupt when there is a stall cycle coming!
|
assign int_condition = (inte_sync_reg && ~exec_stall_reg && ~next_exec_stall && intcon_reg[7]);
|
assign int_condition = (inte_sync_reg && ~exec_stall_reg && intcon_reg[7]);
|
// Interrupt must be pending
|
// Interrupt must be pending
|
// Next processor cycle must not be a stall
|
// Next processor cycle must not be a stall
|
// GIE bit must be set to issue interrupt
|
// GIE bit must be set to issue interrupt
|
|
|
// Circuit's output signals
|
// Circuit's output signals
|