Line 1... |
Line 1... |
-- HF-RISC v3.4
|
-- HF-RISC v3.5
|
-- Sergio Johann Filho, 2011 - 2016
|
-- Sergio Johann Filho, 2011 - 2016
|
--
|
--
|
-- *This is a quick and dirty organization of a 3-stage pipelined MIPS microprocessor. All registers / memory
|
-- *This is a quick and dirty organization of a 3-stage pipelined MIPS microprocessor. All registers / memory
|
-- accesses are synchronized to the rising edge of clock. The same processor could be designed with only 2
|
-- accesses are synchronized to the rising edge of clock. The same processor could be designed with only 2
|
-- pipeline stages, but this would require memories to be either asynchronous (as presented on comp arq text
|
-- pipeline stages, but this would require memories to be either asynchronous (as presented on comp arq text
|
Line 18... |
Line 18... |
-- language in mind, so opcodes which cause overflows on integer operations (add, addi, sub) were not included
|
-- language in mind, so opcodes which cause overflows on integer operations (add, addi, sub) were not included
|
-- for obvious reasons.
|
-- for obvious reasons.
|
-- *Memory is accessed in big endian mode.
|
-- *Memory is accessed in big endian mode.
|
-- *No unaligned loads/stores.
|
-- *No unaligned loads/stores.
|
-- *No co-processor is implemented and all peripherals are memory mapped.
|
-- *No co-processor is implemented and all peripherals are memory mapped.
|
-- *Loads and stores take 2/1 cycles with separated code/data memories and 3 cycles otherwise. This version is organized
|
-- *Loads and stores take 3 cycles. This version is organized as a Von Neumann machine, so there is only one
|
-- as a Von Neumann machine, so there is only one memory interface that is shared betweeen code and data accesses.
|
-- memory interface that is shared betweeen code and data accesses.
|
-- No load delay slots are needed in code.
|
-- No load delay slots are needed in code.
|
-- *Branches have a 1 cycle delay (not taken) or 3 cycle dalay (taken), including two branch delay slots.
|
-- *Branches have a 1 cycle delay (not taken) or 3 cycle dalay (taken), including two branch delay slots.
|
-- This is a side effect of the pipeline refill and memory access policy. All other instructions are single
|
-- This is a side effect of the pipeline refill and memory access policy. All other instructions are single
|
-- cycle. The first delay slot can be filled with an instruction, reducing the cost to 2 cycles. The
|
-- cycle. The first delay slot can be filled with an instruction, reducing the cost to 2 cycles. The
|
-- second delay slot is completely useless and the instruction in this slot is discarded. No branch predictor
|
-- second delay slot is completely useless and the instruction in this slot is discarded. No branch predictor
|
Line 121... |
Line 121... |
reset: in std_logic;
|
reset: in std_logic;
|
|
|
stall: in std_logic;
|
stall: in std_logic;
|
|
|
stall_cpu: out std_logic;
|
stall_cpu: out std_logic;
|
busy_cpu: out std_logic;
|
|
irq_vector_cpu: out std_logic_vector(31 downto 0);
|
irq_vector_cpu: out std_logic_vector(31 downto 0);
|
irq_cpu: out std_logic;
|
irq_cpu: out std_logic;
|
irq_ack_cpu: in std_logic;
|
irq_ack_cpu: in std_logic;
|
inst_addr_cpu: in std_logic_vector(31 downto 0);
|
address_cpu: in std_logic_vector(31 downto 0);
|
inst_in_cpu: out std_logic_vector(31 downto 0);
|
|
data_addr_cpu: in std_logic_vector(31 downto 0);
|
|
data_in_cpu: out std_logic_vector(31 downto 0);
|
data_in_cpu: out std_logic_vector(31 downto 0);
|
data_out_cpu: in std_logic_vector(31 downto 0);
|
data_out_cpu: in std_logic_vector(31 downto 0);
|
data_w_cpu: in std_logic_vector(3 downto 0);
|
data_w_cpu: in std_logic_vector(3 downto 0);
|
data_access_cpu: in std_logic;
|
data_access_cpu: in std_logic;
|
|
|
Line 149... |
Line 146... |
|
|
architecture arch of busmux is
|
architecture arch of busmux is
|
signal write_enable: std_logic;
|
signal write_enable: std_logic;
|
signal irq_cause, irq_mask_reg, uart_divisor: std_logic_vector(15 downto 0);
|
signal irq_cause, irq_mask_reg, uart_divisor: std_logic_vector(15 downto 0);
|
signal irq_status_reg, extio_out_reg: std_logic_vector(7 downto 0);
|
signal irq_status_reg, extio_out_reg: std_logic_vector(7 downto 0);
|
signal irq_vector_reg, irq_epc_reg, compare_reg, counter_reg: std_logic_vector(31 downto 0);
|
signal periph_data, irq_vector_reg, irq_epc_reg, compare_reg, counter_reg: std_logic_vector(31 downto 0);
|
signal compare2_reg: std_logic_vector(23 downto 0);
|
signal compare2_reg: std_logic_vector(23 downto 0);
|
signal interrupt, irq, irq_counter, irq_counter_not, irq_counter2, irq_counter2_not, irq_compare, irq_compare2, compare_trig, compare2_trig: std_logic;
|
signal interrupt, irq, irq_counter, irq_counter_not, irq_counter2, irq_counter2_not, irq_compare, irq_compare2, compare_trig, compare2_trig: std_logic;
|
signal data_read_uart, data_write_uart: std_logic_vector(7 downto 0);
|
signal data_read_uart, data_write_uart: std_logic_vector(7 downto 0);
|
signal enable_uart, enable_uart_read, enable_uart_write, uart_write_busy, uart_data_avail: std_logic;
|
signal enable_uart, enable_uart_read, enable_uart_write, uart_write_busy, uart_data_avail: std_logic;
|
|
|
type pulse_state_type is (irq_idle, irq_int, irq_req, irq_ackn, irq_done);
|
type pulse_state_type is (irq_idle, irq_int, irq_req, irq_ackn, irq_done);
|
signal pulse_state: pulse_state_type;
|
signal pulse_state: pulse_state_type;
|
signal pulse_next_state: pulse_state_type;
|
signal pulse_next_state: pulse_state_type;
|
|
|
signal periph_access, periph_access_we, data_access_cpu_dly, data_access_cpu_dly2: std_logic;
|
signal periph_access, periph_access_dly, periph_access_we: std_logic;
|
signal data_we_mem_s: std_logic_vector(3 downto 0);
|
signal data_we_mem_s: std_logic_vector(3 downto 0);
|
|
|
begin
|
begin
|
-- address decoder, read from peripheral registers
|
-- peripheral register logic, read from peripheral registers
|
process(data_addr_cpu, irq_vector_reg, irq_cause, irq_mask_reg, irq_status_reg, irq_epc_reg, compare_reg, compare2_reg, counter_reg, data_read_uart, uart_divisor, data_read_mem, extio_in, extio_out_reg)
|
process(clock, reset, periph_access, address_cpu, irq_vector_reg, irq_cause, irq_mask_reg, irq_status_reg, irq_epc_reg, compare_reg, compare2_reg, counter_reg, data_read_uart, uart_divisor, data_read_mem, extio_in, extio_out_reg)
|
begin
|
begin
|
case data_addr_cpu(31 downto 27) is
|
if reset = '1' then
|
when "11110" => -- Peripherals (f000 0000 - f7ff ffff)
|
periph_data <= (others => '0');
|
case data_addr_cpu(7 downto 4) is
|
elsif clock'event and clock = '1' then
|
|
if periph_access = '1' then
|
|
case address_cpu(7 downto 4) is
|
when "0000" => -- IRQ_VECTOR (RW)
|
when "0000" => -- IRQ_VECTOR (RW)
|
data_in_cpu <= irq_vector_reg;
|
periph_data <= irq_vector_reg;
|
when "0001" => -- IRQ_CAUSE (RO)
|
when "0001" => -- IRQ_CAUSE (RO)
|
data_in_cpu <= x"0000" & irq_cause;
|
periph_data <= x"0000" & irq_cause;
|
when "0010" => -- IRQ_MASK (RW)
|
when "0010" => -- IRQ_MASK (RW)
|
data_in_cpu <= x"0000" & irq_mask_reg;
|
periph_data <= x"0000" & irq_mask_reg;
|
when "0011" => -- IRQ_STATUS (RW)
|
when "0011" => -- IRQ_STATUS (RW)
|
data_in_cpu <= x"000000" & irq_status_reg;
|
periph_data <= x"000000" & irq_status_reg;
|
when "0100" => -- IRQ_EPC (RO)
|
when "0100" => -- IRQ_EPC (RO)
|
data_in_cpu <= irq_epc_reg;
|
periph_data <= irq_epc_reg;
|
when "0101" => -- COUNTER (RO)
|
when "0101" => -- COUNTER (RO)
|
data_in_cpu <= counter_reg;
|
periph_data <= counter_reg;
|
when "0110" => -- IRQ_COMPARE (RW)
|
when "0110" => -- IRQ_COMPARE (RW)
|
data_in_cpu <= compare_reg;
|
periph_data <= compare_reg;
|
when "0111" => -- IRQ_COMPARE2 (RW)
|
when "0111" => -- IRQ_COMPARE2 (RW)
|
data_in_cpu <= x"00" & compare2_reg;
|
periph_data <= x"00" & compare2_reg;
|
when "1000" => -- EXTIO_IN (RO)
|
when "1000" => -- EXTIO_IN (RO)
|
data_in_cpu <= x"000000" & extio_in;
|
periph_data <= x"000000" & extio_in;
|
when "1001" => -- EXTIO_OUT (RW)
|
when "1001" => -- EXTIO_OUT (RW)
|
data_in_cpu <= x"000000" & extio_out_reg;
|
periph_data <= x"000000" & extio_out_reg;
|
when "1110" => -- UART (RW)
|
when "1110" => -- UART (RW)
|
data_in_cpu <= x"000000" & data_read_uart;
|
periph_data <= x"000000" & data_read_uart;
|
when "1111" => -- UART_DIVISOR (RW)
|
when "1111" => -- UART_DIVISOR (RW)
|
data_in_cpu <= x"0000" & uart_divisor;
|
periph_data <= x"0000" & uart_divisor;
|
when others =>
|
when others =>
|
data_in_cpu <= data_read_mem;
|
periph_data <= data_read_mem;
|
end case;
|
|
when others => -- ROM / RAM area, external peripherals (f800 0000 - ffff fffc)
|
|
data_in_cpu <= data_read_mem;
|
|
end case;
|
end case;
|
|
end if;
|
|
end if;
|
end process;
|
end process;
|
|
|
inst_in_cpu <= data_read_mem;
|
data_in_cpu <= data_read_mem when periph_access_dly = '0' else periph_data;
|
|
|
-- peripheral register logic, write to peripheral registers
|
-- peripheral register logic, write to peripheral registers
|
process(clock, reset, counter_reg, data_addr_cpu, data_out_cpu, periph_access, periph_access_we, irq_ack_cpu)
|
process(clock, reset, counter_reg, address_cpu, data_out_cpu, periph_access, periph_access_we, irq_ack_cpu)
|
begin
|
begin
|
if reset = '1' then
|
if reset = '1' then
|
irq_vector_reg <= x"00000000";
|
irq_vector_reg <= x"00000000";
|
irq_mask_reg <= x"0000";
|
irq_mask_reg <= x"0000";
|
irq_status_reg <= x"00";
|
irq_status_reg <= x"00";
|
Line 226... |
Line 224... |
end if;
|
end if;
|
if compare2_reg = counter_reg(23 downto 0) then
|
if compare2_reg = counter_reg(23 downto 0) then
|
compare2_trig <= '1';
|
compare2_trig <= '1';
|
end if;
|
end if;
|
if periph_access = '1' and periph_access_we = '1' then
|
if periph_access = '1' and periph_access_we = '1' then
|
case data_addr_cpu(7 downto 4) is
|
case address_cpu(7 downto 4) is
|
when "0000" => -- IRQ_VECTOR
|
when "0000" => -- IRQ_VECTOR
|
irq_vector_reg <= data_out_cpu;
|
irq_vector_reg <= data_out_cpu;
|
when "0010" => -- IRQ_MASK
|
when "0010" => -- IRQ_MASK
|
irq_mask_reg <= data_out_cpu(15 downto 0);
|
irq_mask_reg <= data_out_cpu(15 downto 0);
|
when "0011" => -- IRQ_STATUS
|
when "0011" => -- IRQ_STATUS
|
Line 253... |
Line 251... |
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- EPC register register load on interrupts
|
-- EPC register register load on interrupts
|
process(clock, reset, inst_addr_cpu, irq)
|
process(clock, reset, address_cpu, irq)
|
begin
|
begin
|
if reset = '1' then
|
if reset = '1' then
|
irq_epc_reg <= x"00000000";
|
irq_epc_reg <= x"00000000";
|
elsif clock'event and clock = '1' then
|
elsif clock'event and clock = '1' then
|
if irq = '1' and irq_ack_cpu = '0' then
|
if irq = '1' and irq_ack_cpu = '0' then
|
irq_epc_reg <= inst_addr_cpu;
|
irq_epc_reg <= address_cpu;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- interrupt state machine
|
-- interrupt state machine
|
Line 301... |
Line 299... |
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- data / peripheral access delay
|
-- data / peripheral access delay
|
process(clock, reset, irq_ack_cpu, data_access_cpu, stall)
|
process(clock, reset, irq_ack_cpu, periph_access, stall)
|
begin
|
begin
|
if reset = '1' then
|
if reset = '1' then
|
data_access_cpu_dly <= '0';
|
periph_access_dly <= '0';
|
data_access_cpu_dly2 <= '0';
|
|
elsif clock'event and clock = '1' then
|
elsif clock'event and clock = '1' then
|
if stall = '0' then
|
if stall = '0' then
|
data_access_cpu_dly2 <= data_access_cpu_dly;
|
periph_access_dly <= periph_access;
|
if data_access_cpu = '1' and data_access_cpu_dly = '0' and data_access_cpu_dly2 = '0' then
|
|
data_access_cpu_dly <= '1';
|
|
else
|
|
data_access_cpu_dly <= '0';
|
|
end if;
|
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
periph_access <= '1' when data_addr_cpu(31 downto 27) = "11110" and data_access_cpu = '1' else '0';
|
periph_access <= '1' when address_cpu(31 downto 27) = "11110" and data_access_cpu = '1' else '0';
|
periph_access_we <= '1' when periph_access <= '1' and data_w_cpu /= "0000" else '0';
|
periph_access_we <= '1' when periph_access <= '1' and data_w_cpu /= "0000" else '0';
|
|
|
-- memory address / write enable muxes and cpu stall logic
|
-- memory address / write enable muxes and cpu stall logic
|
addr_mem <= data_addr_cpu when data_access_cpu_dly = '0' and data_access_cpu = '1' and periph_access = '0' else inst_addr_cpu;
|
addr_mem <= address_cpu;
|
data_write_mem <= data_out_cpu;
|
data_write_mem <= data_out_cpu;
|
data_we_mem_s <= data_w_cpu when data_access_cpu_dly = '0' and data_access_cpu = '1' and periph_access = '0' else "0000";
|
data_we_mem_s <= data_w_cpu when data_access_cpu = '1' and periph_access = '0' else "0000";
|
data_we_mem <= data_we_mem_s;
|
data_we_mem <= data_we_mem_s;
|
|
|
busy_cpu <= (data_access_cpu and not data_access_cpu_dly); -- load/store: 1 wait cycle
|
|
stall_cpu <= stall;
|
stall_cpu <= stall;
|
|
|
-- interrupts and peripherals
|
-- interrupts and peripherals
|
interrupt <= '0' when (irq_cause and irq_mask_reg) = x"0000" else '1';
|
interrupt <= '0' when (irq_cause and irq_mask_reg) = x"0000" else '1';
|
irq_cause <= extio_in & not uart_write_busy & uart_data_avail & irq_compare2 & irq_compare & irq_counter2_not & irq_counter2 & irq_counter_not & irq_counter;
|
irq_cause <= extio_in & not uart_write_busy & uart_data_avail & irq_compare2 & irq_compare & irq_counter2_not & irq_counter2 & irq_counter_not & irq_counter;
|
Line 349... |
Line 340... |
write_enable <= '1' when data_we_mem_s /= "0000" else '0';
|
write_enable <= '1' when data_we_mem_s /= "0000" else '0';
|
data_write_uart <= data_out_cpu(7 downto 0);
|
data_write_uart <= data_out_cpu(7 downto 0);
|
|
|
uart:
|
uart:
|
if uart_support = "yes" generate
|
if uart_support = "yes" generate
|
enable_uart <= '1' when periph_access = '1' and data_addr_cpu(7 downto 4) = "1110" else '0';
|
enable_uart <= '1' when periph_access = '1' and address_cpu(7 downto 4) = "1110" else '0';
|
enable_uart_write <= enable_uart and periph_access_we;
|
enable_uart_write <= enable_uart and periph_access_we;
|
enable_uart_read <= enable_uart and not periph_access_we;
|
enable_uart_read <= enable_uart and not periph_access_we;
|
|
|
-- a simple UART
|
-- a simple UART
|
serial: entity work.uart
|
serial: entity work.uart
|