Line 68... |
Line 68... |
-- :
|
-- :
|
-- : Enable_NMI overrides the mask bit for interrupt 0, creating a
|
-- : Enable_NMI overrides the mask bit for interrupt 0, creating a
|
-- : non-maskable interrupt at the highest priority. To remain
|
-- : non-maskable interrupt at the highest priority. To remain
|
-- : true to the original core, this should be set false.
|
-- : true to the original core, this should be set false.
|
-- :
|
-- :
|
|
-- : Sequential_Interrupts, when set, prevents interrupt service
|
|
-- : routines from being interrupted by postponing an later
|
|
-- : interrupts until the I bit is cleared (usually with an RTI,
|
|
-- : but a CLP PSR_I will also work). This is potentially
|
|
-- : dangerous, as it means a lower-priority ISR can "hog" the CPU
|
|
-- : by failing to return. However, it can also prevent the
|
|
-- : condition of an ISR interrupting itself until it causes a
|
|
-- : memory fault. (For example, an interrupt source that whose
|
|
-- : period is shorter than the ISR service time) Note that this
|
|
-- : setting alters the way the pending logic works, so it affects
|
|
-- : all interrupts, including the NMI. If this is set, special
|
|
-- : care should be taken to make sure ISRs are short and always
|
|
-- : execute an RTI at the end.
|
|
-- :
|
-- : RTI_Ignores_GP_Flags alters the set of flag bits restored
|
-- : RTI_Ignores_GP_Flags alters the set of flag bits restored
|
-- : after an interrupt. By default, all of the flag bits are put
|
-- : after an interrupt. By default, all of the flag bits are put
|
-- : back to their original state. If this flag is set true, only
|
-- : back to their original state. If this flag is set true, only
|
-- : the lower four bits are restored, allowing ISR code to alter
|
-- : the lower four bits are restored, allowing ISR code to alter
|
-- : the GP flags persistently.
|
-- : the GP flags persistently.
|
Line 86... |
Line 100... |
-- : initialization code may be run in an ISR context, initially
|
-- : initialization code may be run in an ISR context, initially
|
-- : bypassing memory protection. Init code should clear the I bit
|
-- : bypassing memory protection. Init code should clear the I bit
|
-- : when done;
|
-- : when done;
|
-- :
|
-- :
|
-- : Unsigned_Index_Offsets alters the way offsets are added to
|
-- : Unsigned_Index_Offsets alters the way offsets are added to
|
-- : [Rn+1:Rn] during LDO/STO instructions. The original, defeault
|
-- : [Rn+1:Rn] during LDO/STO instructions. The original, default
|
-- : behavior treats these offsets as signed values, allowing
|
-- : behavior treats these offsets as signed values, allowing
|
-- : instructions to offset by -128 to +127 from [Rn+1:Rn].
|
-- : instructions to offset by -128 to +127 from [Rn+1:Rn].
|
-- : Setting this generic to TRUE will switch to unsigned offsets,
|
-- : Setting this generic to TRUE will switch to unsigned offsets,
|
-- : switching the range to 0 to 255 instead.
|
-- : switching the range to 0 to 255 instead.
|
-- :
|
-- :
|
Line 591... |
Line 605... |
-- increment the PC similar to an ISR flow.
|
-- increment the PC similar to an ISR flow.
|
CPU_Next_State <= WAI_Cx;
|
CPU_Next_State <= WAI_Cx;
|
PC_Ctrl.Offset <= PC_NEXT;
|
PC_Ctrl.Offset <= PC_NEXT;
|
else
|
else
|
-- If Break is implemented normally, back the PC up by
|
-- If Break is implemented normally, back the PC up by
|
-- 2 and return through IPF_C0 in order to execute a 5
|
-- 2 and return through IPF_C0 in order to execute a 3
|
-- clock cycle delay
|
-- clock cycle delay
|
CPU_Next_State <= BRK_C1;
|
CPU_Next_State <= BRK_C1;
|
PC_Ctrl.Offset <= PC_REV2;
|
PC_Ctrl.Offset <= PC_REV2;
|
end if;
|
end if;
|
|
|
Line 928... |
Line 942... |
if( Int_Req = '1' )then
|
if( Int_Req = '1' )then
|
CPU_Next_State <= ISR_C1;
|
CPU_Next_State <= ISR_C1;
|
-- Rewind the PC by 3 to put the PC back to would have been the next
|
-- Rewind the PC by 3 to put the PC back to would have been the next
|
-- instruction, compensating for the pipeline registers.
|
-- instruction, compensating for the pipeline registers.
|
PC_Ctrl.Offset <= PC_REV3;
|
PC_Ctrl.Offset <= PC_REV3;
|
-- Reset all of the sub-block controls to IDLE, to avoid unintended
|
|
-- operation due to the current instruction
|
|
DP_Ctrl.Src <= DATA_RD_MEM;
|
DP_Ctrl.Src <= DATA_RD_MEM;
|
end if;
|
end if;
|
|
|
when WAH_Cx => -- Holds until CPU_Halt_Req is deasserted.
|
when WAH_Cx => -- Holds until CPU_Halt_Req is deasserted.
|
CPU_Halt_Ack <= '1';
|
CPU_Halt_Ack <= '1';
|
Line 1028... |
Line 1040... |
variable Sum : std_logic_vector(8 downto 0) := "000000000";
|
variable Sum : std_logic_vector(8 downto 0) := "000000000";
|
variable Temp : std_logic_vector(8 downto 0) := "000000000";
|
variable Temp : std_logic_vector(8 downto 0) := "000000000";
|
begin
|
begin
|
if( Reset = Reset_Level )then
|
if( Reset = Reset_Level )then
|
CPU_State <= IPF_C0;
|
CPU_State <= IPF_C0;
|
|
|
|
CPU_Halt_Req <= '0';
|
|
Halt_Ack <= '0';
|
|
|
Opcode <= OP_INC;
|
Opcode <= OP_INC;
|
SubOp <= ACCUM;
|
SubOp <= ACCUM;
|
SubOp_p1 <= ACCUM;
|
SubOp_p1 <= ACCUM;
|
Operand1 <= x"00";
|
Operand1 <= x"00";
|
Operand2 <= x"00";
|
Operand2 <= x"00";
|
Instr_Prefetch <= '0';
|
Instr_Prefetch <= '0';
|
Prefetch <= x"00";
|
Prefetch <= x"00";
|
|
|
CPU_Halt_Req <= '0';
|
|
Halt_Ack <= '0';
|
|
|
|
Open8_Bus.Wr_En <= '0';
|
Open8_Bus.Wr_En <= '0';
|
Open8_Bus.Wr_Data <= OPEN8_NULLBUS;
|
Open8_Bus.Wr_Data <= OPEN8_NULLBUS;
|
Open8_Bus.Rd_En <= '1';
|
Open8_Bus.Rd_En <= '1';
|
|
|
Program_Ctr <= Program_Start_Addr;
|
Program_Ctr <= Program_Start_Addr;
|
Line 1074... |
Line 1087... |
|
|
Open8_Bus.GP_Flags <= (others => '0');
|
Open8_Bus.GP_Flags <= (others => '0');
|
|
|
elsif( rising_edge(Clock) )then
|
elsif( rising_edge(Clock) )then
|
|
|
|
CPU_State <= CPU_Next_State;
|
|
|
|
-- Register the halt request and acknowledge lines
|
|
|
CPU_Halt_Req <= Halt_Req;
|
CPU_Halt_Req <= Halt_Req;
|
Halt_Ack <= CPU_Halt_Ack;
|
Halt_Ack <= CPU_Halt_Ack;
|
|
|
Open8_Bus.Wr_En <= '0';
|
|
Open8_Bus.Wr_Data <= OPEN8_NULLBUS;
|
|
Open8_Bus.Rd_En <= '0';
|
|
|
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
-- Instruction/Operand caching for pipelined memory access
|
-- Instruction/Operand caching for pipelined memory access
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
CPU_State <= CPU_Next_State;
|
|
|
-- To avoid putting too much load on the (usually massive) wire-OR'd bus,
|
|
-- the CPU loads Rd_Data into one of four registers - instruction,
|
|
-- operand 1 or 2, or the instruction prefetch registers. The first is
|
|
-- used to decode an instruction when the prefetch isn't valid, while
|
|
-- the two operand registers are used to hold any additional argument
|
|
-- for multi-byte instructions. Because of the memory pipelining, some
|
|
-- longer instructions can cache the next instruction as part of their
|
|
-- execution in a prefetch register, allowing the CPU to skip loading
|
|
-- it again later. Unfortunate, because instructions aren't all the same
|
|
-- length, it is not feasible to cache their operands without adding a
|
|
-- second partial decode stage that would obviate any savings.
|
|
|
case Cache_Ctrl is
|
case Cache_Ctrl is
|
when CACHE_INSTR =>
|
when CACHE_INSTR =>
|
Opcode <= Rd_Data(7 downto 3);
|
Opcode <= Rd_Data(7 downto 3);
|
SubOp <= Rd_Data(2 downto 0);
|
SubOp <= Rd_Data(2 downto 0);
|
SubOp_p1 <= Rd_Data(2 downto 0) + 1;
|
SubOp_p1 <= Rd_Data(2 downto 0) + 1;
|
Line 1114... |
Line 1139... |
end case;
|
end case;
|
|
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
-- Program Counter
|
-- Program Counter
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
|
|
|
-- The program counter is a bit unusual in that it always subtracts two
|
|
-- from itself plus the signed offset. This is because of the way the
|
|
-- assembler works when computing branches. Thus, to "IDLE" the counter,
|
|
-- the offset is set to 2, while "NEXT" sets the offset to 3. Depending
|
|
-- on how an instruction interacts with memory, or is pipelined, the
|
|
-- offset can vary from -1 to 3
|
|
|
Offset_SX(15 downto 8) := (others => PC_Ctrl.Offset(7));
|
Offset_SX(15 downto 8) := (others => PC_Ctrl.Offset(7));
|
Offset_SX(7 downto 0) := PC_Ctrl.Offset;
|
Offset_SX(7 downto 0) := PC_Ctrl.Offset;
|
|
|
case PC_Ctrl.Oper is
|
case PC_Ctrl.Oper is
|
when PC_INCR =>
|
when PC_INCR =>
|
Line 1131... |
Line 1164... |
end case;
|
end case;
|
|
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
-- (Write) Data Path
|
-- (Write) Data Path
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
|
|
|
-- Note that this code handles both the Rd_En and Wr_En signals. These
|
|
-- were separated to make downstream logic simpler (As opposed to the
|
|
-- more classic RD_WRn and ADDR_STROBE scheme) It is also true to the
|
|
-- original core, which also had separate read and write enable outputs
|
|
|
|
Open8_Bus.Wr_En <= '0';
|
|
Open8_Bus.Wr_Data <= OPEN8_NULLBUS;
|
|
Open8_Bus.Rd_En <= '0';
|
|
|
case DP_Ctrl.Src is
|
case DP_Ctrl.Src is
|
when DATA_BUS_IDLE =>
|
when DATA_BUS_IDLE =>
|
null;
|
null;
|
|
|
when DATA_RD_MEM =>
|
when DATA_RD_MEM =>
|
Line 1215... |
Line 1258... |
i_Ints := (Interrupts or INT_Ctrl.Soft_Ints) and
|
i_Ints := (Interrupts or INT_Ctrl.Soft_Ints) and
|
Int_Mask;
|
Int_Mask;
|
|
|
Pending <= i_Ints or Pending;
|
Pending <= i_Ints or Pending;
|
|
|
|
-- If Sequential_Interrupts is set true, Wait_for_ISR should follow the
|
|
-- I bit, preventing a new interrupt from starting until the I bit is
|
|
-- cleared.
|
if( Sequential_Interrupts )then
|
if( Sequential_Interrupts )then
|
Wait_for_ISR <= Flags(PSR_I);
|
Wait_for_ISR <= Flags(PSR_I);
|
else
|
else
|
Wait_for_ISR <= '0';
|
Wait_for_ISR <= '0';
|
end if;
|
end if;
|
Line 1269... |
Line 1315... |
end if;
|
end if;
|
|
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
-- ALU (Arithmetic / Logic Unit)
|
-- ALU (Arithmetic / Logic Unit)
|
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
|
|
|
-- The ALU code is responsible for (and should be the only code altering)
|
|
-- the register file. Most of the "instructions" directly map to opcodes
|
|
-- but a few are for internal use only, such as operations involving the
|
|
-- stack pointer of interrupt mask.
|
|
|
Index := conv_integer(ALU_Ctrl.Reg);
|
Index := conv_integer(ALU_Ctrl.Reg);
|
Sum := (others => '0');
|
Sum := (others => '0');
|
Temp := (others => '0');
|
Temp := (others => '0');
|
|
|
case ALU_Ctrl.Oper is
|
case ALU_Ctrl.Oper is
|