OpenCores
URL https://opencores.org/ocsvn/hf-risc/hf-risc/trunk

Subversion Repositories hf-risc

[/] [hf-risc/] [trunk/] [hf-riscv/] [core_rv32i/] [peripherals_busmux.vhd] - Blame information for rev 17

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 17 serginhofr
-- HF-RISCV v1.3
2 13 serginhofr
-- Sergio Johann Filho, 2015 - 2016
3
--
4
-- *This is a quick and dirty organization of a 3-stage pipelined RISC-V microprocessor. All registers / memory
5
--  accesses are synchronized to the rising edge of clock. The same processor could be designed with only 2
6
--  pipeline stages, but this would require memories to be either asynchronous (as presented on comp arq text
7
--  books), double clocked or operating on the opposite edge. Pipeline stages are:
8
--
9
--  FETCH: instruction memory is accessed (address is PC), data becomes available in one cycle. PC is updated.
10
--  DECODE: an instruction is fed into the decoding / control logic and values are registered for the next
11
--  stage. pipeline stalls, as well as bubble insertion is performed in this stage.
12
--  EXECUTE: the register file is accessed and the ALU calculates the result. data access is performed (loads
13
--  and stores) or simply the result (or pc) is written to the register file (normal operations). branch target
14
--  and outcome are calculated.
15
--
16
-- *This design is a compromise between performance, area and complexity.
17
-- *Only the RV32I base instruction set is implemented. FENCE and SYSTEM instructions are missing. SYSTEM
18
--  instructions always trap the processor and can be handled in software.
19
-- *Memory is accessed in little endian mode.
20
-- *No co-processor is implemented and all peripherals are memory mapped.
21
-- *Loads and stores take 2/1 cycles with separated code/data memories and 3 cycles otherwise. This version is organized
22
--  as a Von Neumann machine, so there is only one memory interface that is shared betweeen code and data accesses.
23
-- *Branches have a 1 cycle delay (not taken) or 3 cycle dalay (taken), including two branch delay slots.
24
--  This is a side effect of the pipeline refill and memory access policy. All other instructions are single
25
--  cycle. No branch predictor is implemented (default branch target is 'not taken').
26
-- *Interrupts are handled using VECTOR, CAUSE, MASK, STATUS and EPC registers. The VECTOR register is used to hold
27
--  the address of the default (non-vectored) interrupt handler. The CAUSE register is read only and peripheral
28
--  interrupt lines are connected to this register. The MASK register is read/write and holds the interrupt mask
29
--  for the CAUSE register. The interrupt STATUS register is automatically cleared on interrupts, and is set by
30
--  software when returning from interrupts - this works as a global interrupt enable/disable flag. This register is
31
--  read and write capable, so it can also be cleared by software. Setting this register just before returning
32
--  from interrupts (enable is delayed in a few cycles) re-enables interrupts. The EPC register holds the program
33
--  counter when the processor is interrupted (we should re-execute the last instruction (EPC-4), as it was not
34
--  commited yet). EPC is a read only register, and is used to return from an interrupt using simple LW / JR
35
--  instructions. As an interrupt is accepted, the processor jumps to VECTOR address where the first level of irq
36
--  handling is done. A second level handler (in C) implements the interrupt priority mechanism and calls the
37
--  appropriate ISR for each interrupt.
38
-- *Built in peripherals: running counter (32 bit), two counter comparators (32 and 24 bit), I/O ports and UART. the
39
--  UART baud rate is defined in a 16 bit divisor register. Two counter bits (bits 18 and 16 and their complements) are
40
--  tied to interrupt lines, so are the two counter comparators and the UART.
41
--
42
-- Memory map:
43
--
44
-- ROM                                  0x00000000 - 0x1fffffff (512MB)
45
-- System                               0x20000000 - 0x3fffffff (512MB)
46
-- SRAM                                 0x40000000 - 0x5fffffff (512MB)
47
-- External RAM / device                0x60000000 - 0x9fffffff (1GB)
48
-- External RAM / device                0xa0000000 - 0xdfffffff (1GB)           (uncached)
49
-- External Peripheral                  0xe0000000 - 0xefffffff (256MB)         (uncached)
50
-- Peripheral (core)                    0xf0000000 - 0xf7ffffff (128MB)         (uncached)
51
-- Peripheral (extended)                0xf8000000 - 0xffffffff (128MB)         (uncached)
52
--
53
--   IRQ_VECTOR                 0xf0000000
54
--   IRQ_CAUSE                  0xf0000010
55
--   IRQ_MASK                   0xf0000020
56
--   IRQ_STATUS                 0xf0000030
57
--   IRQ_EPC                    0xf0000040
58
--   COUNTER                    0xf0000050
59
--   COMPARE                    0xf0000060
60
--   COMPARE2                   0xf0000070
61
--   EXTIO_IN                   0xf0000080
62
--   EXTIO_OUT                  0xf0000090
63
--   DEBUG                      0xf00000d0
64
--   UART_WRITE / UART_READ     0xf00000e0
65
--   UART_DIVISOR               0xf00000f0
66
--
67
-- Interrupt masks:
68
--
69
-- IRQ_COUNTER                  0x0001          (bit 18 of the counter is set)
70
-- IRQ_COUNTER_NOT              0x0002          (bit 18 of the counter is clear)
71
-- IRQ_COUNTER2                 0x0004          (bit 16 of the counter is set)
72
-- IRQ_COUNTER2_NOT             0x0008          (bit 16 of the counter is clear)
73
-- IRQ_COMPARE                  0x0010          (counter is equal to compare, clears irq when updated)
74
-- IRQ_COMPARE2                 0x0020          (counter bits 23 to 0 are equal to compare2, clears irq when updated)
75
-- IRQ_UART_READ_AVAILABLE      0x0040          (there is data available for reading on the UART)
76
-- IRQ_UART_WRITE_AVAILABLE     0x0080          (UART is not busy)
77
-- EXT_IRQ0                     0x0100          (external interrupts on extio_in, 'high' level triggered)
78
-- EXT_IRQ1                     0x0200
79
-- EXT_IRQ2                     0x0400
80
-- EXT_IRQ3                     0x0800
81
-- EXT_IRQ4                     0x1000
82
-- EXT_IRQ5                     0x2000
83
-- EXT_IRQ6                     0x4000
84
-- EXT_IRQ7                     0x8000
85
 
86
library ieee;
87
use ieee.std_logic_1164.all;
88
use ieee.std_logic_unsigned.all;
89
use ieee.std_logic_arith.all;
90
 
91
entity busmux is
92
        generic(
93
                log_file: string := "UNUSED";                   -- options are "out.txt" and "UNUSED"
94
                uart_support: string := "no"                    -- options are "yes" and "no".
95
        );
96
        port (  clock:          in std_logic;
97
                reset:          in std_logic;
98
 
99
                stall:          in std_logic;
100
 
101
                stall_cpu:      out std_logic;
102
                busy_cpu:       out std_logic;
103
                irq_vector_cpu: out std_logic_vector(31 downto 0);
104
                irq_cpu:        out std_logic;
105
                irq_ack_cpu:    in std_logic;
106
                exception_cpu:  in std_logic;
107
                inst_addr_cpu:  in std_logic_vector(31 downto 0);
108
                inst_in_cpu:    out std_logic_vector(31 downto 0);
109
                data_addr_cpu:  in std_logic_vector(31 downto 0);
110
                data_in_cpu:    out std_logic_vector(31 downto 0);
111
                data_out_cpu:   in std_logic_vector(31 downto 0);
112
                data_w_cpu:     in std_logic_vector(3 downto 0);
113
                data_access_cpu:        in std_logic;
114
 
115
                addr_mem:       out std_logic_vector(31 downto 0);
116
                data_read_mem:  in std_logic_vector(31 downto 0);
117
                data_write_mem: out std_logic_vector(31 downto 0);
118
                data_we_mem:    out std_logic_vector(3 downto 0);
119
 
120
                extio_in:       in std_logic_vector(7 downto 0);
121
                extio_out:      out std_logic_vector(7 downto 0);
122
                uart_read:      in std_logic;
123
                uart_write:     out std_logic
124
        );
125
end busmux;
126
 
127
architecture arch of busmux is
128
        signal write_enable: std_logic;
129
        signal irq_cause, irq_mask_reg, uart_divisor: std_logic_vector(15 downto 0);
130
        signal irq_status_reg, extio_out_reg: std_logic_vector(7 downto 0);
131
        signal irq_vector_reg, irq_epc_reg, compare_reg, counter_reg: std_logic_vector(31 downto 0);
132
        signal compare2_reg: std_logic_vector(23 downto 0);
133
        signal interrupt, irq, irq_counter, irq_counter_not, irq_counter2, irq_counter2_not, irq_compare, irq_compare2, compare_trig, compare2_trig: std_logic;
134
        signal data_read_uart, data_write_uart: std_logic_vector(7 downto 0);
135
        signal enable_uart, enable_uart_read, enable_uart_write, uart_write_busy, uart_data_avail: std_logic;
136
 
137 17 serginhofr
        type pulse_state_type is (irq_idle, irq_int, irq_req, irq_ackn, irq_done);
138 13 serginhofr
        signal pulse_state: pulse_state_type;
139
        signal pulse_next_state: pulse_state_type;
140
 
141
        signal periph_access, periph_access_we, data_access_cpu_dly, data_access_cpu_dly2: std_logic;
142
        signal data_we_mem_s: std_logic_vector(3 downto 0);
143
 
144
begin
145
        -- address decoder, read from peripheral registers
146
        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)
147
        begin
148
                case data_addr_cpu(31 downto 27) is
149
                        when "11110" =>                         -- Peripherals     (f000 0000 - f7ff ffff)
150
                                case data_addr_cpu(7 downto 4) is
151
                                        when "0000" =>          -- IRQ_VECTOR           (RW)
152
                                                data_in_cpu <= irq_vector_reg;
153
                                        when "0001" =>          -- IRQ_CAUSE            (RO)
154
                                                data_in_cpu <= irq_cause(7 downto 0) & irq_cause(15 downto 8) & x"0000";
155
                                        when "0010" =>          -- IRQ_MASK             (RW)
156
                                                data_in_cpu <= irq_mask_reg(7 downto 0) & irq_mask_reg(15 downto 8) & x"0000";
157
                                        when "0011" =>          -- IRQ_STATUS           (RW)
158
                                                data_in_cpu <= irq_status_reg & x"000000";
159
                                        when "0100" =>          -- IRQ_EPC              (RO)
160
                                                data_in_cpu <= irq_epc_reg(7 downto 0) & irq_epc_reg(15 downto 8) & irq_epc_reg(23 downto 16) & irq_epc_reg(31 downto 24);
161
                                        when "0101" =>          -- COUNTER              (RO)
162
                                                data_in_cpu <= counter_reg(7 downto 0) & counter_reg(15 downto 8) & counter_reg(23 downto 16) & counter_reg(31 downto 24);
163
                                        when "0110" =>          -- IRQ_COMPARE          (RW)
164
                                                data_in_cpu <= compare_reg(7 downto 0) & compare_reg(15 downto 8) & compare_reg(23 downto 16) & compare_reg(31 downto 24);
165
                                        when "0111" =>          -- IRQ_COMPARE2         (RW)
166
                                                data_in_cpu <= compare_reg(15 downto 8) & compare_reg(23 downto 16) & compare_reg(31 downto 24) & x"00";
167
                                        when "1000" =>          -- EXTIO_IN             (RO)
168
                                                data_in_cpu <= extio_in & x"000000";
169
                                        when "1001" =>          -- EXTIO_OUT            (RW)
170
                                                data_in_cpu <= extio_out_reg & x"000000";
171
                                        when "1110" =>          -- UART                 (RW)
172
                                                data_in_cpu <= data_read_uart & x"000000";
173
                                        when "1111" =>          -- UART_DIVISOR         (RW)
174
                                                data_in_cpu <= uart_divisor(7 downto 0) & uart_divisor(15 downto 8) & x"0000";
175
                                        when others =>
176
                                                data_in_cpu <= data_read_mem;
177
                                end case;
178
                        when others =>                          -- ROM / RAM area, external peripherals (f800 0000 - ffff fffc)
179
                                data_in_cpu <= data_read_mem;
180
                end case;
181
        end process;
182
 
183
        inst_in_cpu <= data_read_mem;
184
 
185
        -- peripheral register logic, write to peripheral registers
186
        process(clock, reset, counter_reg, data_addr_cpu, data_out_cpu, periph_access, periph_access_we, irq)
187
        begin
188
                if reset = '1' then
189
                        irq_vector_reg <= x"00000000";
190
                        irq_mask_reg <= x"0000";
191
                        irq_status_reg <= x"00";
192
                        counter_reg <= x"00000000";
193
                        compare_reg <= x"00000000";
194
                        compare_trig <= '0';
195
                        compare2_reg <= x"000000";
196
                        compare2_trig <= '0';
197
                        extio_out_reg <= x"00";
198
                        uart_divisor <= x"0000";
199
                elsif clock'event and clock = '1' then
200
                        counter_reg <= counter_reg + 1;
201
                        if compare_reg = counter_reg then
202
                                compare_trig <= '1';
203
                        end if;
204
                        if compare2_reg = counter_reg(23 downto 0) then
205
                                compare2_trig <= '1';
206
                        end if;
207 17 serginhofr
                        if periph_access = '1' and periph_access_we = '1' then
208
                                case data_addr_cpu(7 downto 4) is
209
                                        when "0000" =>  -- IRQ_VECTOR
210
                                                irq_vector_reg <= data_out_cpu(7 downto 0) & data_out_cpu(15 downto 8) & data_out_cpu(23 downto 16) & data_out_cpu(31 downto 24);
211
                                        when "0010" =>  -- IRQ_MASK
212
                                                irq_mask_reg <= data_out_cpu(23 downto 16) & data_out_cpu(31 downto 24);
213
                                        when "0011" =>  -- IRQ_STATUS
214
                                                irq_status_reg <= data_out_cpu(31 downto 24);
215
                                        when "0110" =>  -- IRQ_COMPARE
216
                                                compare_reg <= data_out_cpu(7 downto 0) & data_out_cpu(15 downto 8) & data_out_cpu(23 downto 16) & data_out_cpu(31 downto 24);
217
                                                compare_trig <= '0';
218
                                        when "0111" =>  -- IRQ_COMPARE2
219
                                                compare2_reg <= data_out_cpu(15 downto 8) & data_out_cpu(23 downto 16) & data_out_cpu(31 downto 24);
220
                                                compare2_trig <= '0';
221
                                        when "1001" =>  -- EXTIO_OUT
222
                                                extio_out_reg <= data_out_cpu(31 downto 24);
223
                                        when "1111" =>  -- UART_DIVISOR
224
                                                uart_divisor <= data_out_cpu(23 downto 16) & data_out_cpu(31 downto 24);
225
                                        when others =>
226
                                end case;
227
                        end if;
228
                        if irq_ack_cpu = '1' or exception_cpu = '1' then
229 13 serginhofr
                                irq_status_reg(0) <= '0';         -- IRQ_STATUS (clear master int bit on interrupt)
230
                        end if;
231
                end if;
232
        end process;
233
 
234
        -- EPC register register load on interrupts
235
        process(clock, reset, inst_addr_cpu, irq, irq_ack_cpu)
236
        begin
237
                if reset = '1' then
238
                        irq_epc_reg <= x"00000000";
239
                elsif clock'event and clock = '1' then
240
                        if ((irq = '1' and irq_ack_cpu = '0') or exception_cpu = '1') then
241
                                irq_epc_reg <= inst_addr_cpu;
242
                        end if;
243
                end if;
244
        end process;
245
 
246
        -- interrupt state machine
247
        process(clock, reset, pulse_state, interrupt, irq_status_reg, stall)
248
        begin
249
                if reset = '1' then
250
                        pulse_state <= irq_idle;
251
                        pulse_next_state <= irq_idle;
252
                        irq <= '0';
253
                elsif clock'event and clock = '1' then
254
                        if stall = '0' then
255
                                pulse_state <= pulse_next_state;
256
                                case pulse_state is
257
                                        when irq_idle =>
258 17 serginhofr
                                                if interrupt = '1' and irq_status_reg(0) = '1' then
259
                                                        pulse_next_state <= irq_int;
260 13 serginhofr
                                                end if;
261
                                        when irq_int =>
262
                                                irq <= '1';
263
                                                pulse_next_state <= irq_req;
264
                                        when irq_req =>
265
                                                if irq_ack_cpu = '1' then
266
                                                        irq <= '0';
267
                                                        pulse_next_state <= irq_ackn;
268
                                                end if;
269
                                        when irq_ackn =>
270
                                                pulse_next_state <= irq_done;
271
                                        when irq_done =>
272
                                                if irq_status_reg(0) = '1' then
273
                                                        pulse_next_state <= irq_idle;
274
                                                end if;
275
                                        when others =>
276
                                                pulse_next_state <= irq_idle;
277
                                end case;
278
                        end if;
279
                end if;
280
        end process;
281
 
282
        -- data / peripheral access delay
283
        process(clock, reset, irq_ack_cpu, data_access_cpu, stall)
284
        begin
285
                if reset = '1' then
286
                        data_access_cpu_dly <= '0';
287
                        data_access_cpu_dly2 <= '0';
288
                elsif clock'event and clock = '1' then
289
                        if stall = '0' then
290
                                data_access_cpu_dly2 <= data_access_cpu_dly;
291
                                if data_access_cpu = '1' and data_access_cpu_dly = '0' and data_access_cpu_dly2 = '0' then
292
                                        data_access_cpu_dly <= '1';
293
                                else
294
                                        data_access_cpu_dly <= '0';
295
                                end if;
296
                        end if;
297
                end if;
298
        end process;
299
 
300
        periph_access <= '1' when data_addr_cpu(31 downto 27) = "11110" and data_access_cpu = '1' else '0';
301
        periph_access_we <= '1' when periph_access <= '1' and data_w_cpu /= "0000" else '0';
302
 
303
        -- memory address / write enable muxes and cpu stall logic
304
        addr_mem <= data_addr_cpu when data_access_cpu_dly = '0' and data_access_cpu = '1' and periph_access = '0' else inst_addr_cpu;
305
        data_write_mem <= data_out_cpu;
306
        data_we_mem_s <= data_w_cpu when data_access_cpu_dly = '0' and data_access_cpu = '1' and periph_access = '0' else "0000";
307
        data_we_mem <= data_we_mem_s;
308
 
309
        busy_cpu <= (data_access_cpu and not data_access_cpu_dly);                                      -- load/store: 1 wait cycle
310
        stall_cpu <= stall;
311
 
312
        -- interrupts and peripherals
313
        interrupt <= '0' when (irq_cause and irq_mask_reg) = x"0000" else '1';
314
        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;
315
 
316
        irq_cpu <= irq;
317
        irq_vector_cpu <= irq_vector_reg;
318
        irq_counter <= counter_reg(18);
319
        irq_counter_not <= not counter_reg(18);
320
        irq_counter2 <= counter_reg(16);
321
        irq_counter2_not <= not counter_reg(16);
322
        irq_compare <= '1' when compare_trig = '1' else '0';
323
        irq_compare2 <= '1' when compare2_trig = '1' else '0';
324
        extio_out <= extio_out_reg;
325
 
326
        write_enable <= '1' when data_we_mem_s /= "0000" else '0';
327
        data_write_uart <= data_out_cpu(31 downto 24);
328
 
329
        uart:
330
        if uart_support = "yes" generate
331
                enable_uart <= '1' when periph_access = '1' and data_addr_cpu(7 downto 4) = "1110" else '0';
332
                enable_uart_write <= enable_uart and periph_access_we;
333
                enable_uart_read <= enable_uart and not periph_access_we;
334
 
335
                -- a simple UART
336
                serial: entity work.uart
337
                generic map (log_file => log_file)
338
                port map(
339
                        clk             => clock,
340
                        reset           => reset,
341
                        divisor         => uart_divisor(11 downto 0),
342
                        enable_read     => enable_uart_read,
343
                        enable_write    => enable_uart_write,
344
                        data_in         => data_write_uart,
345
                        data_out        => data_read_uart,
346
                        uart_read       => uart_read,
347
                        uart_write      => uart_write,
348
                        busy_write      => uart_write_busy,
349
                        data_avail      => uart_data_avail
350
                );
351
        end generate;
352
 
353
        no_uart:
354
        if uart_support = "no" generate
355
                enable_uart <= '0';
356
                data_read_uart <= (others => '0');
357
                uart_write_busy <= '0';
358
                uart_data_avail <= '0';
359
        end generate;
360
 
361
end arch;
362
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.