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

Subversion Repositories hf-risc

[/] [hf-risc/] [trunk/] [hf-risc/] [ucore/] [peripherals_busmux.vhd] - Blame information for rev 19

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 18 serginhofr
-- HF-RISC v3.5
2 13 serginhofr
-- Sergio Johann Filho, 2011 - 2016
3
--
4
-- *This is a quick and dirty organization of a 3-stage pipelined MIPS 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 absolutely *needed* MIPS-I opcodes are implemented. This core was implemented with the C programming
18
--  language in mind, so opcodes which cause overflows on integer operations (add, addi, sub) were not included
19
--  for obvious reasons.
20
-- *Memory is accessed in big endian mode.
21
-- *No unaligned loads/stores.
22
-- *No co-processor is implemented and all peripherals are memory mapped.
23 18 serginhofr
-- *Loads and stores take 3 cycles. This version is organized as a Von Neumann machine, so there is only one
24
--  memory interface that is shared betweeen code and data accesses.
25 13 serginhofr
--  No load delay slots are needed in code.
26
-- *Branches have a 1 cycle delay (not taken) or 3 cycle dalay (taken), including two branch delay slots.
27
--  This is a side effect of the pipeline refill and memory access policy. All other instructions are single
28
--  cycle. The first delay slot can be filled with an instruction, reducing the cost to 2 cycles. The
29
--  second delay slot is completely useless and the instruction in this slot is discarded. No branch predictor
30
--  is implemented (default branch target is 'not taken'). Minor modifications in the datapath can turn the second
31
--  branch delay slot usable, but the current toolchain isn't compatible with this behavior, so a bubble is inserted.
32
-- *Interrupts are handled using VECTOR, CAUSE, MASK, STATUS and EPC registers. The VECTOR register is used to hold
33
--  the address of the default (non-vectored) interrupt handler. The CAUSE register is read only and peripheral
34
--  interrupt lines are connected to this register. The MASK register is read/write and holds the interrupt mask
35
--  for the CAUSE register. The interrupt STATUS register is automatically cleared on interrupts, and is set by
36
--  software when returning from interrupts - this works as a global interrupt enable/disable flag. This register is
37
--  read and write capable, so it can also be cleared by software. Setting this register on return from interrupts
38
--  (normally in the branch delay slot) re-enables interrupts. The EPC register holds the program counter when
39
--  the processor is interrupted (we should re-execute the last instruction (EPC-4), as it was not commited yet).
40
--  EPC is a read only register, and is used to return from an interrupt using simple LW / JR --  instructions.
41
--  As an interrupt is accepted, the processor jumps to VECTOR address where the first level of irq handling is
42
--  done. A second level handler (in C) implements the interrupt priority mechanism and calls the appropriate
43
--  ISR for each interrupt.
44
-- *Built in peripherals: running counter (32 bit), two counter comparators (32 and 24 bit), I/O ports and UART. the
45
--  UART baud rate is defined in a 16 bit divisor register. Two counter bits (bits 18 and 16 and their complements) are
46
--  tied to interrupt lines, so are the two counter comparators and the UART.
47
--
48
-- *Compiler:
49
--  Patched GCC version 4.9.3.
50
--  Mandatory gcc options are: -mips1(**) -mpatfree -mfix-r4000 -mno-check-zero-division -msoft-float -fshort-double
51
--               -nostdinc -fno-builtin -fomit-frame-pointer -G 0 -mnohwmult -mnohwdiv -ffixed-lo -ffixed-hi
52
--
53
-- (**) "-mips2 -mno-branch-likely" can be used instead of "-mips1". the result is similar to the code generated
54
--      with "-mips1", but no useless nops are inserted after loads on data hazards (load delay slots).
55
--
56
-- *The following instructions from the MIPS I instruction set were implemented (41 opcodes):
57
--     Arithmetic Instructions: addiu, addu, subu
58
--     Logic Instructions: and, andi, nor, or, ori, xor, xori
59
--     Shift Instructions: sll, sra, srl, sllv, srav, srlv
60
--     Comparison Instructions: slt, sltu, slti, sltiu
61
--     Load/Store Instructions: lui, lb, lbu, lh, lhu, lw, sb, sh, sw
62
--     Branch Instructions: beq, bne, bgez, bgezal, bgtz, blez, bltzal, bltz
63
--     Jump Instructions: j, jal, jr, jalr
64
--
65
--
66
-- Memory map:
67
--
68
-- ROM                                  0x00000000 - 0x1fffffff (512MB)
69
-- System                               0x20000000 - 0x3fffffff (512MB)
70
-- SRAM                                 0x40000000 - 0x5fffffff (512MB)
71
-- External RAM / device                0x60000000 - 0x9fffffff (1GB)
72
-- External RAM / device                0xa0000000 - 0xdfffffff (1GB)           (uncached)
73
-- External Peripheral                  0xe0000000 - 0xefffffff (256MB)         (uncached)
74
-- Peripheral (core)                    0xf0000000 - 0xf7ffffff (128MB)         (uncached)
75
-- Peripheral (extended)                0xf8000000 - 0xffffffff (128MB)         (uncached)
76
--
77
--   IRQ_VECTOR                 0xf0000000
78
--   IRQ_CAUSE                  0xf0000010
79
--   IRQ_MASK                   0xf0000020
80
--   IRQ_STATUS                 0xf0000030
81
--   IRQ_EPC                    0xf0000040
82
--   COUNTER                    0xf0000050
83
--   COMPARE                    0xf0000060
84
--   COMPARE2                   0xf0000070
85
--   EXTIO_IN                   0xf0000080
86
--   EXTIO_OUT                  0xf0000090
87
--   DEBUG                      0xf00000d0
88
--   UART_WRITE / UART_READ     0xf00000e0
89
--   UART_DIVISOR               0xf00000f0
90
--
91
-- Interrupt masks:
92
--
93 19 serginhofr
-- IRQ_COUNTER                  0x00000001              (bit 18 of the counter is set)
94
-- IRQ_COUNTER_NOT              0x00000002              (bit 18 of the counter is clear)
95
-- IRQ_COUNTER2                 0x00000004              (bit 16 of the counter is set)
96
-- IRQ_COUNTER2_NOT             0x00000008              (bit 16 of the counter is clear)
97
-- IRQ_COMPARE                  0x00000010              (counter is equal to compare, clears irq when updated)
98
-- IRQ_COMPARE2                 0x00000020              (counter bits 23 to 0 are equal to compare2, clears irq when updated)
99
-- IRQ_UART_READ_AVAILABLE      0x00000040              (there is data available for reading on the UART)
100
-- IRQ_UART_WRITE_AVAILABLE     0x00000080              (UART is not busy)
101
-- EXT_IRQ0                     0x00010000              (external interrupts on extio_in, high level triggered)
102
-- EXT_IRQ1                     0x00020000
103
-- EXT_IRQ2                     0x00040000
104
-- EXT_IRQ3                     0x00080000
105
-- EXT_IRQ4                     0x00100000
106
-- EXT_IRQ5                     0x00200000
107
-- EXT_IRQ6                     0x00400000
108
-- EXT_IRQ7                     0x00800000
109
-- EXT_IRQ0_NOT                 0x01000000              (external interrupts on extio_in, low level triggered)
110
-- EXT_IRQ1_NOT                 0x02000000
111
-- EXT_IRQ2_NOT                 0x04000000
112
-- EXT_IRQ3_NOT                 0x08000000
113
-- EXT_IRQ4_NOT                 0x10000000
114
-- EXT_IRQ5_NOT                 0x20000000
115
-- EXT_IRQ6_NOT                 0x40000000
116
-- EXT_IRQ7_NOT                 0x80000000
117 13 serginhofr
 
118
library ieee;
119
use ieee.std_logic_1164.all;
120
use ieee.std_logic_unsigned.all;
121
use ieee.std_logic_arith.all;
122
 
123
entity busmux is
124
        generic(
125
                log_file: string := "UNUSED";                   -- options are "out.txt" and "UNUSED"
126
                uart_support: string := "no"                    -- options are "yes" and "no".
127
        );
128
        port (  clock:          in std_logic;
129
                reset:          in std_logic;
130
 
131
                stall:          in std_logic;
132
 
133
                stall_cpu:      out std_logic;
134
                irq_vector_cpu: out std_logic_vector(31 downto 0);
135
                irq_cpu:        out std_logic;
136
                irq_ack_cpu:    in std_logic;
137 18 serginhofr
                address_cpu:    in std_logic_vector(31 downto 0);
138 13 serginhofr
                data_in_cpu:    out std_logic_vector(31 downto 0);
139
                data_out_cpu:   in std_logic_vector(31 downto 0);
140
                data_w_cpu:     in std_logic_vector(3 downto 0);
141
                data_access_cpu:        in std_logic;
142
 
143
                addr_mem:       out std_logic_vector(31 downto 0);
144
                data_read_mem:  in std_logic_vector(31 downto 0);
145
                data_write_mem: out std_logic_vector(31 downto 0);
146
                data_we_mem:    out std_logic_vector(3 downto 0);
147
 
148
                extio_in:       in std_logic_vector(7 downto 0);
149
                extio_out:      out std_logic_vector(7 downto 0);
150
                uart_read:      in std_logic;
151
                uart_write:     out std_logic
152
        );
153
end busmux;
154
 
155
architecture arch of busmux is
156
        signal write_enable: std_logic;
157 19 serginhofr
        signal uart_divisor: std_logic_vector(15 downto 0);
158 13 serginhofr
        signal irq_status_reg, extio_out_reg: std_logic_vector(7 downto 0);
159 19 serginhofr
        signal periph_data, irq_vector_reg, irq_cause, irq_mask_reg, irq_epc_reg, compare_reg, counter_reg: std_logic_vector(31 downto 0);
160 13 serginhofr
        signal compare2_reg: std_logic_vector(23 downto 0);
161
        signal interrupt, irq, irq_counter, irq_counter_not, irq_counter2, irq_counter2_not, irq_compare, irq_compare2, compare_trig, compare2_trig: std_logic;
162
        signal data_read_uart, data_write_uart: std_logic_vector(7 downto 0);
163
        signal enable_uart, enable_uart_read, enable_uart_write, uart_write_busy, uart_data_avail: std_logic;
164
 
165 17 serginhofr
        type pulse_state_type is (irq_idle, irq_int, irq_req, irq_ackn, irq_done);
166 13 serginhofr
        signal pulse_state: pulse_state_type;
167
        signal pulse_next_state: pulse_state_type;
168
 
169 18 serginhofr
        signal periph_access, periph_access_dly, periph_access_we: std_logic;
170 13 serginhofr
        signal data_we_mem_s: std_logic_vector(3 downto 0);
171
 
172
begin
173 18 serginhofr
        -- peripheral register logic, read from peripheral registers
174
        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)
175 13 serginhofr
        begin
176 18 serginhofr
                if reset = '1' then
177
                        periph_data <= (others => '0');
178
                elsif clock'event and clock = '1' then
179
                        if periph_access = '1' then
180
                                case address_cpu(7 downto 4) is
181 13 serginhofr
                                        when "0000" =>          -- IRQ_VECTOR           (RW)
182 18 serginhofr
                                                periph_data <= irq_vector_reg;
183 13 serginhofr
                                        when "0001" =>          -- IRQ_CAUSE            (RO)
184 19 serginhofr
                                                periph_data <= irq_cause;
185 13 serginhofr
                                        when "0010" =>          -- IRQ_MASK             (RW)
186 19 serginhofr
                                                periph_data <= irq_mask_reg;
187 13 serginhofr
                                        when "0011" =>          -- IRQ_STATUS           (RW)
188 18 serginhofr
                                                periph_data <= x"000000" & irq_status_reg;
189 13 serginhofr
                                        when "0100" =>          -- IRQ_EPC              (RO)
190 18 serginhofr
                                                periph_data <= irq_epc_reg;
191 13 serginhofr
                                        when "0101" =>          -- COUNTER              (RO)
192 18 serginhofr
                                                periph_data <= counter_reg;
193 13 serginhofr
                                        when "0110" =>          -- IRQ_COMPARE          (RW)
194 18 serginhofr
                                                periph_data <= compare_reg;
195 13 serginhofr
                                        when "0111" =>          -- IRQ_COMPARE2         (RW)
196 18 serginhofr
                                                periph_data <= x"00" & compare2_reg;
197 13 serginhofr
                                        when "1000" =>          -- EXTIO_IN             (RO)
198 18 serginhofr
                                                periph_data <= x"000000" & extio_in;
199 13 serginhofr
                                        when "1001" =>          -- EXTIO_OUT            (RW)
200 18 serginhofr
                                                periph_data <= x"000000" & extio_out_reg;
201 13 serginhofr
                                        when "1110" =>          -- UART                 (RW)
202 18 serginhofr
                                                periph_data <= x"000000" & data_read_uart;
203 13 serginhofr
                                        when "1111" =>          -- UART_DIVISOR         (RW)
204 18 serginhofr
                                                periph_data <= x"0000" & uart_divisor;
205 13 serginhofr
                                        when others =>
206 18 serginhofr
                                                periph_data <= data_read_mem;
207 13 serginhofr
                                end case;
208 18 serginhofr
                        end if;
209
                end if;
210 13 serginhofr
        end process;
211
 
212 18 serginhofr
        data_in_cpu <= data_read_mem when periph_access_dly = '0' else periph_data;
213 13 serginhofr
 
214
        -- peripheral register logic, write to peripheral registers
215 18 serginhofr
        process(clock, reset, counter_reg, address_cpu, data_out_cpu, periph_access, periph_access_we, irq_ack_cpu)
216 13 serginhofr
        begin
217
                if reset = '1' then
218 19 serginhofr
                        irq_vector_reg <= (others => '0');
219
                        irq_mask_reg <= (others => '0');
220
                        irq_status_reg <= (others => '0');
221
                        counter_reg <= (others => '0');
222
                        compare_reg <= (others => '0');
223 13 serginhofr
                        compare_trig <= '0';
224 19 serginhofr
                        compare2_reg <= (others => '0');
225 13 serginhofr
                        compare2_trig <= '0';
226 19 serginhofr
                        extio_out_reg <= (others => '0');
227
                        uart_divisor <= (others => '0');
228 13 serginhofr
                elsif clock'event and clock = '1' then
229
                        counter_reg <= counter_reg + 1;
230
                        if compare_reg = counter_reg then
231
                                compare_trig <= '1';
232
                        end if;
233
                        if compare2_reg = counter_reg(23 downto 0) then
234
                                compare2_trig <= '1';
235
                        end if;
236 17 serginhofr
                        if periph_access = '1' and periph_access_we = '1' then
237 18 serginhofr
                                case address_cpu(7 downto 4) is
238 17 serginhofr
                                        when "0000" =>  -- IRQ_VECTOR
239
                                                irq_vector_reg <= data_out_cpu;
240
                                        when "0010" =>  -- IRQ_MASK
241 19 serginhofr
                                                irq_mask_reg <= data_out_cpu;
242 17 serginhofr
                                        when "0011" =>  -- IRQ_STATUS
243
                                                irq_status_reg <= data_out_cpu(7 downto 0);
244
                                        when "0110" =>  -- IRQ_COMPARE
245
                                                compare_reg <= data_out_cpu;
246
                                                compare_trig <= '0';
247
                                        when "0111" =>  -- IRQ_COMPARE2
248
                                                compare2_reg <= data_out_cpu(23 downto 0);
249
                                                compare2_trig <= '0';
250
                                        when "1001" =>  -- EXTIO_OUT
251
                                                extio_out_reg <= data_out_cpu(7 downto 0);
252
                                        when "1111" =>  -- UART_DIVISOR
253
                                                uart_divisor <= data_out_cpu(15 downto 0);
254
                                        when others =>
255
                                end case;
256
                        end if;
257
                        if irq_ack_cpu = '1' then
258 13 serginhofr
                                irq_status_reg(0) <= '0';         -- IRQ_STATUS (clear master int bit on interrupt)
259
                        end if;
260
                end if;
261
        end process;
262
 
263
        -- EPC register register load on interrupts
264 18 serginhofr
        process(clock, reset, address_cpu, irq)
265 13 serginhofr
        begin
266
                if reset = '1' then
267
                        irq_epc_reg <= x"00000000";
268
                elsif clock'event and clock = '1' then
269
                        if irq = '1' and irq_ack_cpu = '0' then
270 18 serginhofr
                                irq_epc_reg <= address_cpu;
271 13 serginhofr
                        end if;
272
                end if;
273
        end process;
274
 
275
        -- interrupt state machine
276
        process(clock, reset, pulse_state, interrupt, irq_status_reg, stall)
277
        begin
278
                if reset = '1' then
279
                        pulse_state <= irq_idle;
280
                        pulse_next_state <= irq_idle;
281
                        irq <= '0';
282
                elsif clock'event and clock = '1' then
283
                        if stall = '0' then
284
                                pulse_state <= pulse_next_state;
285
                                case pulse_state is
286
                                        when irq_idle =>
287 17 serginhofr
                                                if interrupt = '1' and irq_status_reg(0) = '1' then
288
                                                        pulse_next_state <= irq_int;
289 13 serginhofr
                                                end if;
290
                                        when irq_int =>
291
                                                irq <= '1';
292
                                                pulse_next_state <= irq_req;
293
                                        when irq_req =>
294
                                                if irq_ack_cpu = '1' then
295
                                                        irq <= '0';
296
                                                        pulse_next_state <= irq_ackn;
297
                                                end if;
298
                                        when irq_ackn =>
299
                                                pulse_next_state <= irq_done;
300
                                        when irq_done =>
301
                                                if irq_status_reg(0) = '1' then
302
                                                        pulse_next_state <= irq_idle;
303
                                                end if;
304
                                        when others =>
305
                                                pulse_next_state <= irq_idle;
306
                                end case;
307
                        end if;
308
                end if;
309
        end process;
310
 
311
        -- data / peripheral access delay
312 18 serginhofr
        process(clock, reset, irq_ack_cpu, periph_access, stall)
313 13 serginhofr
        begin
314
                if reset = '1' then
315 18 serginhofr
                        periph_access_dly <= '0';
316 13 serginhofr
                elsif clock'event and clock = '1' then
317
                        if stall = '0' then
318 18 serginhofr
                                periph_access_dly <= periph_access;
319 13 serginhofr
                        end if;
320
                end if;
321
        end process;
322
 
323 18 serginhofr
        periph_access <= '1' when address_cpu(31 downto 27) = "11110" and data_access_cpu = '1' else '0';
324 13 serginhofr
        periph_access_we <= '1' when periph_access <= '1' and data_w_cpu /= "0000" else '0';
325
 
326
        -- memory address / write enable muxes and cpu stall logic
327 18 serginhofr
        addr_mem <= address_cpu;
328 13 serginhofr
        data_write_mem <= data_out_cpu;
329 18 serginhofr
        data_we_mem_s <= data_w_cpu when data_access_cpu = '1' and periph_access = '0' else "0000";
330 13 serginhofr
        data_we_mem <= data_we_mem_s;
331
 
332
        stall_cpu <= stall;
333
 
334
        -- interrupts and peripherals
335
        interrupt <= '0' when (irq_cause and irq_mask_reg) = x"0000" else '1';
336 19 serginhofr
        irq_cause <= not extio_in & extio_in & x"00" & not uart_write_busy & uart_data_avail & irq_compare2 & irq_compare & irq_counter2_not & irq_counter2 & irq_counter_not & irq_counter;
337 13 serginhofr
 
338
        irq_cpu <= irq;
339
        irq_vector_cpu <= irq_vector_reg;
340
        irq_counter <= counter_reg(18);
341
        irq_counter_not <= not counter_reg(18);
342
        irq_counter2 <= counter_reg(16);
343
        irq_counter2_not <= not counter_reg(16);
344
        irq_compare <= '1' when compare_trig = '1' else '0';
345
        irq_compare2 <= '1' when compare2_trig = '1' else '0';
346
        extio_out <= extio_out_reg;
347
 
348
        write_enable <= '1' when data_we_mem_s /= "0000" else '0';
349
        data_write_uart <= data_out_cpu(7 downto 0);
350
 
351
        uart:
352
        if uart_support = "yes" generate
353 18 serginhofr
                enable_uart <= '1' when periph_access = '1' and address_cpu(7 downto 4) = "1110" else '0';
354 13 serginhofr
                enable_uart_write <= enable_uart and periph_access_we;
355
                enable_uart_read <= enable_uart and not periph_access_we;
356
 
357
                -- a simple UART
358
                serial: entity work.uart
359
                generic map (log_file => log_file)
360
                port map(
361
                        clk             => clock,
362
                        reset           => reset,
363
                        divisor         => uart_divisor(11 downto 0),
364
                        enable_read     => enable_uart_read,
365
                        enable_write    => enable_uart_write,
366
                        data_in         => data_write_uart,
367
                        data_out        => data_read_uart,
368
                        uart_read       => uart_read,
369
                        uart_write      => uart_write,
370
                        busy_write      => uart_write_busy,
371
                        data_avail      => uart_data_avail
372
                );
373
        end generate;
374
 
375
        no_uart:
376
        if uart_support = "no" generate
377
                enable_uart <= '0';
378
                data_read_uart <= (others => '0');
379
                uart_write_busy <= '0';
380
                uart_data_avail <= '0';
381
        end generate;
382
 
383
end arch;
384
 

powered by: WebSVN 2.1.0

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