URL
https://opencores.org/ocsvn/altor32/altor32/trunk
Subversion Repositories altor32
Compare Revisions
- This comparison shows the changes necessary to convert path
/altor32/trunk
- from Rev 31 to Rev 32
- ↔ Reverse comparison
Rev 31 → Rev 32
/rtl/soc/dmem_mux3.v
1,3 → 1,39
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: |
5,40 → 41,50
module dmem_mux3 |
( |
// Outputs |
out0_addr_o, |
out0_data_o, |
out0_data_i, |
out0_wr_o, |
out0_rd_o, |
out0_burst_o, |
out0_ack_i, |
out0_accept_i, |
out1_addr_o, |
out1_data_o, |
out1_data_i, |
out1_wr_o, |
out1_rd_o, |
out1_burst_o, |
out1_ack_i, |
out1_accept_i, |
out2_addr_o, |
out2_data_o, |
out2_data_i, |
out2_wr_o, |
out2_rd_o, |
out2_burst_o, |
out2_ack_i, |
out2_accept_i, |
output reg [31:0] out0_addr_o, |
output reg [31:0] out0_data_o, |
input [31:0] out0_data_i, |
output reg [3:0] out0_sel_o, |
output reg out0_we_o, |
output reg out0_stb_o, |
output reg out0_cyc_o, |
output reg [2:0] out0_cti_o, |
input out0_ack_i, |
input out0_stall_i, |
|
output reg [31:0] out1_addr_o, |
output reg [31:0] out1_data_o, |
input [31:0] out1_data_i, |
output reg [3:0] out1_sel_o, |
output reg out1_we_o, |
output reg out1_stb_o, |
output reg out1_cyc_o, |
output reg [2:0] out1_cti_o, |
input out1_ack_i, |
input out1_stall_i, |
|
output reg [31:0] out2_addr_o, |
output reg [31:0] out2_data_o, |
input [31:0] out2_data_i, |
output reg [3:0] out2_sel_o, |
output reg out2_we_o, |
output reg out2_stb_o, |
output reg out2_cyc_o, |
output reg [2:0] out2_cti_o, |
input out2_ack_i, |
input out2_stall_i, |
|
// Input |
mem_addr_i, |
mem_data_i, |
mem_data_o, |
mem_burst_i, |
mem_wr_i, |
mem_rd_i, |
mem_ack_o, |
mem_accept_o |
input [31:0] mem_addr_i, |
input [31:0] mem_data_i, |
output reg[31:0] mem_data_o, |
input [3:0] mem_sel_i, |
input mem_we_i, |
input mem_stb_i, |
input mem_cyc_i, |
input [2:0] mem_cti_i, |
output reg mem_ack_o, |
output reg mem_stall_o |
); |
|
//----------------------------------------------------------------- |
47,87 → 93,32
parameter ADDR_MUX_START = 28; |
|
//----------------------------------------------------------------- |
// I/O |
// Request |
//----------------------------------------------------------------- |
input [31:0] mem_addr_i /*verilator public*/; |
input [31:0] mem_data_i /*verilator public*/; |
output [31:0] mem_data_o /*verilator public*/; |
input [3:0] mem_wr_i /*verilator public*/; |
input mem_rd_i /*verilator public*/; |
input mem_burst_i /*verilator public*/; |
output mem_ack_o /*verilator public*/; |
output mem_accept_o /*verilator public*/; |
output [31:0] out0_addr_o /*verilator public*/; |
output [31:0] out0_data_o /*verilator public*/; |
input [31:0] out0_data_i /*verilator public*/; |
output [3:0] out0_wr_o /*verilator public*/; |
output out0_rd_o /*verilator public*/; |
output out0_burst_o /*verilator public*/; |
input out0_ack_i /*verilator public*/; |
input out0_accept_i /*verilator public*/; |
output [31:0] out1_addr_o /*verilator public*/; |
output [31:0] out1_data_o /*verilator public*/; |
input [31:0] out1_data_i /*verilator public*/; |
output [3:0] out1_wr_o /*verilator public*/; |
output out1_rd_o /*verilator public*/; |
output out1_burst_o /*verilator public*/; |
input out1_ack_i /*verilator public*/; |
input out1_accept_i /*verilator public*/; |
output [31:0] out2_addr_o /*verilator public*/; |
output [31:0] out2_data_o /*verilator public*/; |
input [31:0] out2_data_i /*verilator public*/; |
output [3:0] out2_wr_o /*verilator public*/; |
output out2_rd_o /*verilator public*/; |
output out2_burst_o /*verilator public*/; |
input out2_ack_i /*verilator public*/; |
input out2_accept_i /*verilator public*/; |
|
//----------------------------------------------------------------- |
// Registers |
//----------------------------------------------------------------- |
|
// Output Signals |
reg mem_ack_o; |
reg mem_accept_o; |
reg [31:0] mem_data_o; |
|
reg [31:0] out0_addr_o; |
reg [31:0] out0_data_o; |
reg [3:0] out0_wr_o; |
reg out0_rd_o; |
reg out0_burst_o; |
reg [31:0] out1_addr_o; |
reg [31:0] out1_data_o; |
reg [3:0] out1_wr_o; |
reg out1_rd_o; |
reg out1_burst_o; |
reg [31:0] out2_addr_o; |
reg [31:0] out2_data_o; |
reg [3:0] out2_wr_o; |
reg out2_rd_o; |
reg out2_burst_o; |
|
//----------------------------------------------------------------- |
// Memory Map |
//----------------------------------------------------------------- |
always @ (mem_addr_i or mem_wr_i or mem_rd_i or mem_data_i or mem_burst_i) |
always @ * |
begin |
|
out0_addr_o = 32'h00000000; |
out0_wr_o = 4'b0000; |
out0_rd_o = 1'b0; |
out0_data_o = 32'h00000000; |
out0_burst_o = 1'b0; |
out0_sel_o = 4'b0000; |
out0_we_o = 1'b0; |
out0_stb_o = 1'b0; |
out0_cyc_o = 1'b0; |
out0_cti_o = 3'b0; |
out1_addr_o = 32'h00000000; |
out1_wr_o = 4'b0000; |
out1_rd_o = 1'b0; |
out1_data_o = 32'h00000000; |
out1_burst_o = 1'b0; |
out1_sel_o = 4'b0000; |
out1_we_o = 1'b0; |
out1_stb_o = 1'b0; |
out1_cyc_o = 1'b0; |
out1_cti_o = 3'b0; |
out2_addr_o = 32'h00000000; |
out2_wr_o = 4'b0000; |
out2_rd_o = 1'b0; |
out2_data_o = 32'h00000000; |
out2_burst_o = 1'b0; |
out2_sel_o = 4'b0000; |
out2_we_o = 1'b0; |
out2_stb_o = 1'b0; |
out2_cyc_o = 1'b0; |
out2_cti_o = 3'b0; |
|
case (mem_addr_i[ADDR_MUX_START+2-1:ADDR_MUX_START]) |
|
134,26 → 125,32
2'd0: |
begin |
out0_addr_o = mem_addr_i; |
out0_wr_o = mem_wr_i; |
out0_rd_o = mem_rd_i; |
out0_data_o = mem_data_i; |
out0_burst_o = mem_burst_i; |
out0_sel_o = mem_sel_i; |
out0_we_o = mem_we_i; |
out0_stb_o = mem_stb_i; |
out0_cyc_o = mem_cyc_i; |
out0_cti_o = mem_cti_i; |
end |
2'd1: |
begin |
out1_addr_o = mem_addr_i; |
out1_wr_o = mem_wr_i; |
out1_rd_o = mem_rd_i; |
out1_data_o = mem_data_i; |
out1_burst_o = mem_burst_i; |
out1_sel_o = mem_sel_i; |
out1_we_o = mem_we_i; |
out1_stb_o = mem_stb_i; |
out1_cyc_o = mem_cyc_i; |
out1_cti_o = mem_cti_i; |
end |
2'd2: |
begin |
out2_addr_o = mem_addr_i; |
out2_wr_o = mem_wr_i; |
out2_rd_o = mem_rd_i; |
out2_data_o = mem_data_i; |
out2_burst_o = mem_burst_i; |
out2_sel_o = mem_sel_i; |
out2_we_o = mem_we_i; |
out2_stb_o = mem_stb_i; |
out2_cyc_o = mem_cyc_i; |
out2_cti_o = mem_cti_i; |
end |
|
default : |
162,7 → 159,7
end |
|
//----------------------------------------------------------------- |
// Read Port |
// Response |
//----------------------------------------------------------------- |
always @ * |
begin |
171,19 → 168,19
2'd0: |
begin |
mem_data_o = out0_data_i; |
mem_accept_o = out0_accept_i; |
mem_stall_o = out0_stall_i; |
mem_ack_o = out0_ack_i; |
end |
2'd1: |
begin |
mem_data_o = out1_data_i; |
mem_accept_o = out1_accept_i; |
mem_stall_o = out1_stall_i; |
mem_ack_o = out1_ack_i; |
end |
2'd2: |
begin |
mem_data_o = out2_data_i; |
mem_accept_o = out2_accept_i; |
mem_stall_o = out2_stall_i; |
mem_ack_o = out2_ack_i; |
end |
|
190,7 → 187,7
default : |
begin |
mem_data_o = 32'h00000000; |
mem_accept_o = 1'b0; |
mem_stall_o = 1'b0; |
mem_ack_o = 1'b0; |
end |
endcase |
/rtl/soc/soc.v
1,3 → 1,39
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: |
10,20 → 46,13
ext_intr_i, |
intr_o, |
|
|
|
|
|
|
|
|
|
// Memory interface |
io_addr_i, |
io_data_i, |
io_data_o, |
io_wr_i, |
io_rd_i |
io_we_i, |
io_stb_i, |
io_ack_o |
); |
|
//----------------------------------------------------------------- |
30,9 → 59,6
// Params |
//----------------------------------------------------------------- |
parameter [31:0] CLK_KHZ = 12288; |
parameter [31:0] UART_BAUD = 115200; |
parameter [31:0] SPI_FLASH_CLK_KHZ = (12288/2); |
parameter SD_CLK_KHZ = 8000; |
parameter [31:0] EXTERNAL_INTERRUPTS = 1; |
parameter SYSTICK_INTR_MS = 1; |
parameter ENABLE_SYSTICK_TIMER = "ENABLED"; |
46,37 → 72,22
input [(EXTERNAL_INTERRUPTS - 1):0] ext_intr_i /*verilator public*/; |
output intr_o /*verilator public*/; |
|
|
// Memory Port |
input [31:0] io_addr_i /*verilator public*/; |
input [31:0] io_data_i /*verilator public*/; |
output [31:0] io_data_o /*verilator public*/; |
input [3:0] io_wr_i /*verilator public*/; |
input io_rd_i /*verilator public*/; |
input io_we_i /*verilator public*/; |
input io_stb_i /*verilator public*/; |
output io_ack_o /*verilator public*/; |
|
|
|
|
|
|
|
|
//----------------------------------------------------------------- |
// Registers / Wires |
//----------------------------------------------------------------- |
|
|
|
|
|
|
|
|
wire [7:0] timer_addr; |
wire [31:0] timer_data_o; |
wire [31:0] timer_data_i; |
wire [3:0] timer_wr; |
wire timer_rd; |
wire timer_we; |
wire timer_stb; |
wire timer_intr_systick; |
wire timer_intr_hires; |
|
83,8 → 94,8
wire [7:0] intr_addr; |
wire [31:0] intr_data_o; |
wire [31:0] intr_data_i; |
wire [3:0] intr_wr; |
wire intr_rd; |
wire intr_we; |
wire intr_stb; |
|
//----------------------------------------------------------------- |
// Peripheral Interconnect |
101,8 → 112,9
.io_addr_i(io_addr_i), |
.io_data_i(io_data_i), |
.io_data_o(io_data_o), |
.io_wr_i(io_wr_i), |
.io_rd_i(io_rd_i), |
.io_we_i(io_we_i), |
.io_stb_i(io_stb_i), |
.io_ack_o(io_ack_o), |
|
// Peripherals |
// Unused = 0x12000000 - 0x120000FF |
109,88 → 121,60
.periph0_addr_o(/*open*/), |
.periph0_data_o(/*open*/), |
.periph0_data_i(32'h00000000), |
.periph0_wr_o(/*open*/), |
.periph0_rd_o(/*open*/), |
.periph0_we_o(/*open*/), |
.periph0_stb_o(/*open*/), |
|
// Timer = 0x12000100 - 0x120001FF |
.periph1_addr_o(timer_addr), |
.periph1_data_o(timer_data_o), |
.periph1_data_i(timer_data_i), |
.periph1_wr_o(timer_wr), |
.periph1_rd_o(timer_rd), |
.periph1_we_o(timer_we), |
.periph1_stb_o(timer_stb), |
|
// Interrupt Controller = 0x12000200 - 0x120002FF |
.periph2_addr_o(intr_addr), |
.periph2_data_o(intr_data_o), |
.periph2_data_i(intr_data_i), |
.periph2_wr_o(intr_wr), |
.periph2_rd_o(intr_rd), |
.periph2_we_o(intr_we), |
.periph2_stb_o(intr_stb), |
|
// Unused = 0x12000300 - 0x120003FF |
.periph3_addr_o(/*open*/), |
.periph3_data_o(/*open*/), |
.periph3_data_i(32'h00000000), |
.periph3_wr_o(/*open*/), |
.periph3_rd_o(/*open*/), |
.periph3_we_o(/*open*/), |
.periph3_stb_o(/*open*/), |
|
// Unused = 0x12000400 - 0x120004FF |
.periph4_addr_o(/*open*/), |
.periph4_data_o(/*open*/), |
.periph4_data_i(32'h00000000), |
.periph4_wr_o(/*open*/), |
.periph4_rd_o(/*open*/), |
.periph4_we_o(/*open*/), |
.periph4_stb_o(/*open*/), |
|
// Unused = 0x12000500 - 0x120005FF |
.periph5_addr_o(/*open*/), |
.periph5_data_o(/*open*/), |
.periph5_data_i(32'h00000000), |
.periph5_wr_o(/*open*/), |
.periph5_rd_o(/*open*/), |
.periph5_we_o(/*open*/), |
.periph5_stb_o(/*open*/), |
|
// Unused = 0x12000600 - 0x120006FF |
.periph6_addr_o(/*open*/), |
.periph6_data_o(/*open*/), |
.periph6_data_i(32'h00000000), |
.periph6_wr_o(/*open*/), |
.periph6_rd_o(/*open*/), |
.periph6_we_o(/*open*/), |
.periph6_stb_o(/*open*/), |
|
// Unused = 0x12000700 - 0x120007FF |
.periph7_addr_o(/*open*/), |
.periph7_data_o(/*open*/), |
.periph7_data_i(32'h00000000), |
.periph7_wr_o(/*open*/), |
.periph7_rd_o(/*open*/) |
.periph7_we_o(/*open*/), |
.periph7_stb_o(/*open*/) |
); |
|
//----------------------------------------------------------------- |
// Memory master arbiter |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// UART |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// GPIO |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// SPI Flash Master |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// DMA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// SD |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Generic Register |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Timer |
//----------------------------------------------------------------- |
timer_periph |
209,8 → 193,8
.addr_i(timer_addr), |
.data_o(timer_data_i), |
.data_i(timer_data_o), |
.wr_i(timer_wr), |
.rd_i(timer_rd) |
.we_i(timer_we), |
.stb_i(timer_stb) |
); |
|
//----------------------------------------------------------------- |
244,8 → 228,8
.addr_i(intr_addr), |
.data_o(intr_data_i), |
.data_i(intr_data_o), |
.wr_i(intr_wr), |
.rd_i(intr_rd) |
.we_i(intr_we), |
.stb_i(intr_stb) |
); |
|
//------------------------------------------------------------------- |
/rtl/soc/cpu_if.v
1,3 → 1,39
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: |
5,126 → 41,92
module cpu_if |
( |
// General - Clocking & Reset |
clk_i, |
rst_i, |
input clk_i, |
input rst_i, |
|
// Instruction Memory 0 (0x10000000 - 0x10FFFFFF) |
imem0_addr_o, |
imem0_rd_o, |
imem0_burst_o, |
imem0_data_in_i, |
imem0_accept_i, |
imem0_ack_i, |
output [31:0] imem0_addr_o, |
input [31:0] imem0_data_i, |
output [3:0] imem0_sel_o, |
output imem0_stb_o, |
output imem0_cyc_o, |
output [2:0] imem0_cti_o, |
input imem0_ack_i, |
input imem0_stall_i, |
|
// Data Memory 0 (0x10000000 - 0x10FFFFFF) |
dmem0_addr_o, |
dmem0_data_o, |
dmem0_data_i, |
dmem0_wr_o, |
dmem0_rd_o, |
dmem0_burst_o, |
dmem0_accept_i, |
dmem0_ack_i, |
output [31:0] dmem0_addr_o, |
output [31:0] dmem0_data_o, |
input [31:0] dmem0_data_i, |
output [3:0] dmem0_sel_o, |
output dmem0_we_o, |
output dmem0_stb_o, |
output dmem0_cyc_o, |
output [2:0] dmem0_cti_o, |
input dmem0_ack_i, |
input dmem0_stall_i, |
|
// Data Memory 1 (0x11000000 - 0x11FFFFFF) |
dmem1_addr_o, |
dmem1_data_o, |
dmem1_data_i, |
dmem1_wr_o, |
dmem1_rd_o, |
dmem1_burst_o, |
dmem1_accept_i, |
dmem1_ack_i, |
output [31:0] dmem1_addr_o, |
output [31:0] dmem1_data_o, |
input [31:0] dmem1_data_i, |
output [3:0] dmem1_sel_o, |
output dmem1_we_o, |
output dmem1_stb_o, |
output dmem1_cyc_o, |
output [2:0] dmem1_cti_o, |
input dmem1_ack_i, |
input dmem1_stall_i, |
|
// Data Memory 2 (0x12000000 - 0x12FFFFFF) |
dmem2_addr_o, |
dmem2_data_o, |
dmem2_data_i, |
dmem2_wr_o, |
dmem2_rd_o, |
dmem2_burst_o, |
dmem2_accept_i, |
dmem2_ack_i, |
output [31:0] dmem2_addr_o, |
output [31:0] dmem2_data_o, |
input [31:0] dmem2_data_i, |
output [3:0] dmem2_sel_o, |
output dmem2_we_o, |
output dmem2_stb_o, |
output dmem2_cyc_o, |
output [2:0] dmem2_cti_o, |
input dmem2_ack_i, |
input dmem2_stall_i, |
|
fault_o, |
break_o, |
intr_i, |
nmi_i |
output fault_o, |
output break_o, |
input intr_i, |
input nmi_i |
); |
|
//----------------------------------------------------------------- |
// Params |
//----------------------------------------------------------------- |
parameter [31:0] CLK_KHZ = 12288; |
parameter CLK_KHZ = 12288; |
parameter ENABLE_ICACHE = "ENABLED"; |
parameter ENABLE_DCACHE = "DISABLED"; |
parameter ENABLE_DCACHE = "ENABLED"; |
parameter BOOT_VECTOR = 0; |
parameter ISR_VECTOR = 0; |
parameter REGISTER_FILE_TYPE = "SIMULATION"; |
|
//----------------------------------------------------------------- |
// I/O |
//----------------------------------------------------------------- |
input clk_i /*verilator public*/; |
input rst_i /*verilator public*/; |
|
// Instruction Memory 0 (0x10000000 - 0x10FFFFFF) |
output [31:0] imem0_addr_o /*verilator public*/; |
output imem0_rd_o /*verilator public*/; |
output imem0_burst_o /*verilator public*/; |
input [31:0] imem0_data_in_i /*verilator public*/; |
input imem0_accept_i /*verilator public*/; |
input imem0_ack_i /*verilator public*/; |
|
// Data Memory 0 (0x10000000 - 0x10FFFFFF) |
output [31:0] dmem0_addr_o /*verilator public*/; |
output [31:0] dmem0_data_o /*verilator public*/; |
input [31:0] dmem0_data_i /*verilator public*/; |
output [3:0] dmem0_wr_o /*verilator public*/; |
output dmem0_rd_o /*verilator public*/; |
output dmem0_burst_o /*verilator public*/; |
input dmem0_accept_i /*verilator public*/; |
input dmem0_ack_i /*verilator public*/; |
// Data Memory 1 (0x11000000 - 0x11FFFFFF) |
output [31:0] dmem1_addr_o /*verilator public*/; |
output [31:0] dmem1_data_o /*verilator public*/; |
input [31:0] dmem1_data_i /*verilator public*/; |
output [3:0] dmem1_wr_o /*verilator public*/; |
output dmem1_rd_o /*verilator public*/; |
output dmem1_burst_o /*verilator public*/; |
input dmem1_accept_i /*verilator public*/; |
input dmem1_ack_i /*verilator public*/; |
// Data Memory 2 (0x12000000 - 0x12FFFFFF) |
output [31:0] dmem2_addr_o /*verilator public*/; |
output [31:0] dmem2_data_o /*verilator public*/; |
input [31:0] dmem2_data_i /*verilator public*/; |
output [3:0] dmem2_wr_o /*verilator public*/; |
output dmem2_rd_o /*verilator public*/; |
output dmem2_burst_o /*verilator public*/; |
input dmem2_accept_i /*verilator public*/; |
input dmem2_ack_i /*verilator public*/; |
|
output fault_o /*verilator public*/; |
output break_o /*verilator public*/; |
input nmi_i /*verilator public*/; |
input intr_i /*verilator public*/; |
|
//----------------------------------------------------------------- |
// Registers |
//----------------------------------------------------------------- |
wire [31:0] cpu_address; |
wire [3:0] cpu_wr; |
wire cpu_rd; |
wire cpu_burst; |
wire [31:0] cpu_data_w; |
wire [31:0] cpu_data_r; |
wire cpu_accept; |
wire cpu_ack; |
wire [31:0] dmem_addr; |
wire [31:0] dmem_data_w; |
wire [31:0] dmem_data_r; |
wire [3:0] dmem_sel; |
wire [2:0] dmem_cti; |
wire dmem_cyc; |
wire dmem_we; |
wire dmem_stb; |
wire dmem_stall; |
wire dmem_ack; |
|
wire [31:0] imem_address; |
wire [31:0] imem_data; |
wire imem_rd; |
wire imem_burst; |
wire [2:0] imem_cti; |
wire imem_cyc; |
wire imem_stb; |
wire imem_stall; |
wire imem_ack; |
wire imem_accept; |
|
//----------------------------------------------------------------- |
// CPU core |
151,21 → 153,24
|
// Instruction memory |
.imem_addr_o(imem_address), |
.imem_rd_o(imem_rd), |
.imem_burst_o(imem_burst), |
.imem_data_in_i(imem_data), |
.imem_accept_i(imem_accept), |
.imem_ack_i(imem_ack), |
.imem_dat_i(imem_data), |
.imem_cti_o(imem_cti), |
.imem_cyc_o(imem_cyc), |
.imem_stb_o(imem_stb), |
.imem_stall_i(imem_stall), |
.imem_ack_i(imem_ack), |
|
// Data memory |
.dmem_addr_o(cpu_address), |
.dmem_data_out_o(cpu_data_w), |
.dmem_data_in_i(cpu_data_r), |
.dmem_wr_o(cpu_wr), |
.dmem_rd_o(cpu_rd), |
.dmem_burst_o(cpu_burst), |
.dmem_accept_i(cpu_accept), |
.dmem_ack_i(cpu_ack) |
.dmem_addr_o(dmem_addr), |
.dmem_dat_o(dmem_data_w), |
.dmem_dat_i(dmem_data_r), |
.dmem_sel_o(dmem_sel), |
.dmem_cti_o(dmem_cti), |
.dmem_cyc_o(dmem_cyc), |
.dmem_we_o(dmem_we), |
.dmem_stb_o(dmem_stb), |
.dmem_stall_i(dmem_stall), |
.dmem_ack_i(dmem_ack) |
); |
|
//----------------------------------------------------------------- |
173,10 → 178,12
//----------------------------------------------------------------- |
|
assign imem0_addr_o = imem_address; |
assign imem0_rd_o = imem_rd; |
assign imem0_burst_o = imem_burst; |
assign imem_data = imem0_data_in_i; |
assign imem_accept = imem0_accept_i; |
assign imem0_sel_o = 4'b1111; |
assign imem0_stb_o = imem_stb; |
assign imem0_cyc_o = imem_cyc; |
assign imem0_cti_o = imem_cti; |
assign imem_data = imem0_data_i; |
assign imem_stall = imem0_stall_i; |
assign imem_ack = imem0_ack_i; |
|
|
194,39 → 201,49
.out0_addr_o(dmem0_addr_o), |
.out0_data_o(dmem0_data_o), |
.out0_data_i(dmem0_data_i), |
.out0_wr_o(dmem0_wr_o), |
.out0_rd_o(dmem0_rd_o), |
.out0_burst_o(dmem0_burst_o), |
.out0_sel_o(dmem0_sel_o), |
.out0_we_o(dmem0_we_o), |
.out0_stb_o(dmem0_stb_o), |
.out0_cyc_o(dmem0_cyc_o), |
.out0_cti_o(dmem0_cti_o), |
.out0_ack_i(dmem0_ack_i), |
.out0_accept_i(dmem0_accept_i), |
.out0_stall_i(dmem0_stall_i), |
|
// 0x11000000 - 0x11FFFFFF |
.out1_addr_o(dmem1_addr_o), |
.out1_data_o(dmem1_data_o), |
.out1_data_i(dmem1_data_i), |
.out1_wr_o(dmem1_wr_o), |
.out1_rd_o(dmem1_rd_o), |
.out1_burst_o(dmem1_burst_o), |
.out1_sel_o(dmem1_sel_o), |
.out1_we_o(dmem1_we_o), |
.out1_stb_o(dmem1_stb_o), |
.out1_cyc_o(dmem1_cyc_o), |
.out1_cti_o(dmem1_cti_o), |
.out1_ack_i(dmem1_ack_i), |
.out1_accept_i(dmem1_accept_i), |
.out1_stall_i(dmem1_stall_i), |
|
// 0x12000000 - 0x12FFFFFF |
.out2_addr_o(dmem2_addr_o), |
.out2_data_o(dmem2_data_o), |
.out2_data_i(dmem2_data_i), |
.out2_wr_o(dmem2_wr_o), |
.out2_rd_o(dmem2_rd_o), |
.out2_burst_o(dmem2_burst_o), |
.out2_sel_o(dmem2_sel_o), |
.out2_we_o(dmem2_we_o), |
.out2_stb_o(dmem2_stb_o), |
.out2_cyc_o(dmem2_cyc_o), |
.out2_cti_o(dmem2_cti_o), |
.out2_ack_i(dmem2_ack_i), |
.out2_accept_i(dmem2_accept_i), |
.out2_stall_i(dmem2_stall_i), |
|
// Input - CPU core bus |
.mem_addr_i(cpu_address), |
.mem_data_i(cpu_data_w), |
.mem_data_o(cpu_data_r), |
.mem_wr_i(cpu_wr), |
.mem_rd_i(cpu_rd), |
.mem_burst_i(cpu_burst), |
.mem_ack_o(cpu_ack), |
.mem_accept_o(cpu_accept) |
.mem_addr_i(dmem_addr), |
.mem_data_i(dmem_data_w), |
.mem_data_o(dmem_data_r), |
.mem_sel_i(dmem_sel), |
.mem_we_i(dmem_we), |
.mem_stb_i(dmem_stb), |
.mem_cyc_i(dmem_cyc), |
.mem_cti_i(dmem_cti), |
.mem_ack_o(dmem_ack), |
.mem_stall_o(dmem_stall) |
); |
|
endmodule |
/rtl/soc/soc_pif8.v
1,3 → 1,39
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: |
5,190 → 41,109
module soc_pif8 |
( |
// General - Clocking & Reset |
clk_i, |
rst_i, |
input clk_i, |
input rst_i, |
|
// Peripherals |
periph0_addr_o, |
periph0_data_o, |
periph0_data_i, |
periph0_wr_o, |
periph0_rd_o, |
periph1_addr_o, |
periph1_data_o, |
periph1_data_i, |
periph1_wr_o, |
periph1_rd_o, |
periph2_addr_o, |
periph2_data_o, |
periph2_data_i, |
periph2_wr_o, |
periph2_rd_o, |
periph3_addr_o, |
periph3_data_o, |
periph3_data_i, |
periph3_wr_o, |
periph3_rd_o, |
periph4_addr_o, |
periph4_data_o, |
periph4_data_i, |
periph4_wr_o, |
periph4_rd_o, |
periph5_addr_o, |
periph5_data_o, |
periph5_data_i, |
periph5_wr_o, |
periph5_rd_o, |
periph6_addr_o, |
periph6_data_o, |
periph6_data_i, |
periph6_wr_o, |
periph6_rd_o, |
periph7_addr_o, |
periph7_data_o, |
periph7_data_i, |
periph7_wr_o, |
periph7_rd_o, |
output [7:0] periph0_addr_o, |
output [31:0] periph0_data_o, |
input [31:0] periph0_data_i, |
output reg periph0_we_o, |
output reg periph0_stb_o, |
|
// I/O bus |
io_addr_i, |
io_data_i, |
io_data_o, |
io_wr_i, |
io_rd_i |
); |
output [7:0] periph1_addr_o, |
output [31:0] periph1_data_o, |
input [31:0] periph1_data_i, |
output reg periph1_we_o, |
output reg periph1_stb_o, |
|
//----------------------------------------------------------------- |
// I/O |
//----------------------------------------------------------------- |
input clk_i /*verilator public*/; |
input rst_i /*verilator public*/; |
output [7:0] periph2_addr_o, |
output [31:0] periph2_data_o, |
input [31:0] periph2_data_i, |
output reg periph2_we_o, |
output reg periph2_stb_o, |
|
input [31:0] io_addr_i /*verilator public*/; |
output [31:0] io_data_o /*verilator public*/; |
input [31:0] io_data_i /*verilator public*/; |
input [3:0] io_wr_i /*verilator public*/; |
input io_rd_i /*verilator public*/; |
output [7:0] periph3_addr_o, |
output [31:0] periph3_data_o, |
input [31:0] periph3_data_i, |
output reg periph3_we_o, |
output reg periph3_stb_o, |
|
output [7:0] periph0_addr_o /*verilator public*/; |
output [31:0] periph0_data_o /*verilator public*/; |
input [31:0] periph0_data_i /*verilator public*/; |
output [3:0] periph0_wr_o /*verilator public*/; |
output periph0_rd_o /*verilator public*/; |
output [7:0] periph1_addr_o /*verilator public*/; |
output [31:0] periph1_data_o /*verilator public*/; |
input [31:0] periph1_data_i /*verilator public*/; |
output [3:0] periph1_wr_o /*verilator public*/; |
output periph1_rd_o /*verilator public*/; |
output [7:0] periph2_addr_o /*verilator public*/; |
output [31:0] periph2_data_o /*verilator public*/; |
input [31:0] periph2_data_i /*verilator public*/; |
output [3:0] periph2_wr_o /*verilator public*/; |
output periph2_rd_o /*verilator public*/; |
output [7:0] periph3_addr_o /*verilator public*/; |
output [31:0] periph3_data_o /*verilator public*/; |
input [31:0] periph3_data_i /*verilator public*/; |
output [3:0] periph3_wr_o /*verilator public*/; |
output periph3_rd_o /*verilator public*/; |
output [7:0] periph4_addr_o /*verilator public*/; |
output [31:0] periph4_data_o /*verilator public*/; |
input [31:0] periph4_data_i /*verilator public*/; |
output [3:0] periph4_wr_o /*verilator public*/; |
output periph4_rd_o /*verilator public*/; |
output [7:0] periph5_addr_o /*verilator public*/; |
output [31:0] periph5_data_o /*verilator public*/; |
input [31:0] periph5_data_i /*verilator public*/; |
output [3:0] periph5_wr_o /*verilator public*/; |
output periph5_rd_o /*verilator public*/; |
output [7:0] periph6_addr_o /*verilator public*/; |
output [31:0] periph6_data_o /*verilator public*/; |
input [31:0] periph6_data_i /*verilator public*/; |
output [3:0] periph6_wr_o /*verilator public*/; |
output periph6_rd_o /*verilator public*/; |
output [7:0] periph7_addr_o /*verilator public*/; |
output [31:0] periph7_data_o /*verilator public*/; |
input [31:0] periph7_data_i /*verilator public*/; |
output [3:0] periph7_wr_o /*verilator public*/; |
output periph7_rd_o /*verilator public*/; |
output [7:0] periph4_addr_o, |
output [31:0] periph4_data_o, |
input [31:0] periph4_data_i, |
output reg periph4_we_o, |
output reg periph4_stb_o, |
|
//----------------------------------------------------------------- |
// Registers |
//----------------------------------------------------------------- |
reg [3:0] r_mem_sel; |
output [7:0] periph5_addr_o, |
output [31:0] periph5_data_o, |
input [31:0] periph5_data_i, |
output reg periph5_we_o, |
output reg periph5_stb_o, |
|
reg [31:0] io_data_o; |
output [7:0] periph6_addr_o, |
output [31:0] periph6_data_o, |
input [31:0] periph6_data_i, |
output reg periph6_we_o, |
output reg periph6_stb_o, |
|
reg [7:0] periph0_addr_o; |
reg [31:0] periph0_data_o; |
reg [3:0] periph0_wr_o; |
reg periph0_rd_o; |
reg [7:0] periph1_addr_o; |
reg [31:0] periph1_data_o; |
reg [3:0] periph1_wr_o; |
reg periph1_rd_o; |
reg [7:0] periph2_addr_o; |
reg [31:0] periph2_data_o; |
reg [3:0] periph2_wr_o; |
reg periph2_rd_o; |
reg [7:0] periph3_addr_o; |
reg [31:0] periph3_data_o; |
reg [3:0] periph3_wr_o; |
reg periph3_rd_o; |
reg [7:0] periph4_addr_o; |
reg [31:0] periph4_data_o; |
reg [3:0] periph4_wr_o; |
reg periph4_rd_o; |
reg [7:0] periph5_addr_o; |
reg [31:0] periph5_data_o; |
reg [3:0] periph5_wr_o; |
reg periph5_rd_o; |
reg [7:0] periph6_addr_o; |
reg [31:0] periph6_data_o; |
reg [3:0] periph6_wr_o; |
reg periph6_rd_o; |
reg [7:0] periph7_addr_o; |
reg [31:0] periph7_data_o; |
reg [3:0] periph7_wr_o; |
reg periph7_rd_o; |
output [7:0] periph7_addr_o, |
output [31:0] periph7_data_o, |
input [31:0] periph7_data_i, |
output reg periph7_we_o, |
output reg periph7_stb_o, |
|
// I/O bus |
input [31:0] io_addr_i, |
input [31:0] io_data_i, |
output reg [31:0] io_data_o, |
input io_we_i, |
input io_stb_i, |
output reg io_ack_o |
); |
|
//----------------------------------------------------------------- |
// Memory Map |
//----------------------------------------------------------------- |
always @ (io_addr_i or io_wr_i or io_rd_i or io_data_i) |
|
// Route data / address to all peripherals |
assign periph0_addr_o = io_addr_i[7:0]; |
assign periph0_data_o = io_data_i; |
assign periph1_addr_o = io_addr_i[7:0]; |
assign periph1_data_o = io_data_i; |
assign periph2_addr_o = io_addr_i[7:0]; |
assign periph2_data_o = io_data_i; |
assign periph3_addr_o = io_addr_i[7:0]; |
assign periph3_data_o = io_data_i; |
assign periph4_addr_o = io_addr_i[7:0]; |
assign periph4_data_o = io_data_i; |
assign periph5_addr_o = io_addr_i[7:0]; |
assign periph5_data_o = io_data_i; |
assign periph6_addr_o = io_addr_i[7:0]; |
assign periph6_data_o = io_data_i; |
assign periph7_addr_o = io_addr_i[7:0]; |
assign periph7_data_o = io_data_i; |
|
// Select correct target |
always @ * |
begin |
|
periph0_addr_o = 8'h00; |
periph0_wr_o = 4'b0000; |
periph0_rd_o = 1'b0; |
periph0_data_o = 32'h00000000; |
periph1_addr_o = 8'h00; |
periph1_wr_o = 4'b0000; |
periph1_rd_o = 1'b0; |
periph1_data_o = 32'h00000000; |
periph2_addr_o = 8'h00; |
periph2_wr_o = 4'b0000; |
periph2_rd_o = 1'b0; |
periph2_data_o = 32'h00000000; |
periph3_addr_o = 8'h00; |
periph3_wr_o = 4'b0000; |
periph3_rd_o = 1'b0; |
periph3_data_o = 32'h00000000; |
periph4_addr_o = 8'h00; |
periph4_wr_o = 4'b0000; |
periph4_rd_o = 1'b0; |
periph4_data_o = 32'h00000000; |
periph5_addr_o = 8'h00; |
periph5_wr_o = 4'b0000; |
periph5_rd_o = 1'b0; |
periph5_data_o = 32'h00000000; |
periph6_addr_o = 8'h00; |
periph6_wr_o = 4'b0000; |
periph6_rd_o = 1'b0; |
periph6_data_o = 32'h00000000; |
periph7_addr_o = 8'h00; |
periph7_wr_o = 4'b0000; |
periph7_rd_o = 1'b0; |
periph7_data_o = 32'h00000000; |
periph0_we_o = 1'b0; |
periph0_stb_o = 1'b0; |
periph1_we_o = 1'b0; |
periph1_stb_o = 1'b0; |
periph2_we_o = 1'b0; |
periph2_stb_o = 1'b0; |
periph3_we_o = 1'b0; |
periph3_stb_o = 1'b0; |
periph4_we_o = 1'b0; |
periph4_stb_o = 1'b0; |
periph5_we_o = 1'b0; |
periph5_stb_o = 1'b0; |
periph6_we_o = 1'b0; |
periph6_stb_o = 1'b0; |
periph7_we_o = 1'b0; |
periph7_stb_o = 1'b0; |
|
// Decode 4-bit peripheral select |
case (io_addr_i[11:8]) |
196,66 → 151,50
// Peripheral 0 |
4'd 0 : |
begin |
periph0_addr_o = io_addr_i[7:0]; |
periph0_wr_o = io_wr_i; |
periph0_rd_o = io_rd_i; |
periph0_data_o = io_data_i; |
periph0_we_o = io_we_i; |
periph0_stb_o = io_stb_i; |
end |
// Peripheral 1 |
4'd 1 : |
begin |
periph1_addr_o = io_addr_i[7:0]; |
periph1_wr_o = io_wr_i; |
periph1_rd_o = io_rd_i; |
periph1_data_o = io_data_i; |
periph1_we_o = io_we_i; |
periph1_stb_o = io_stb_i; |
end |
// Peripheral 2 |
4'd 2 : |
begin |
periph2_addr_o = io_addr_i[7:0]; |
periph2_wr_o = io_wr_i; |
periph2_rd_o = io_rd_i; |
periph2_data_o = io_data_i; |
periph2_we_o = io_we_i; |
periph2_stb_o = io_stb_i; |
end |
// Peripheral 3 |
4'd 3 : |
begin |
periph3_addr_o = io_addr_i[7:0]; |
periph3_wr_o = io_wr_i; |
periph3_rd_o = io_rd_i; |
periph3_data_o = io_data_i; |
periph3_we_o = io_we_i; |
periph3_stb_o = io_stb_i; |
end |
// Peripheral 4 |
4'd 4 : |
begin |
periph4_addr_o = io_addr_i[7:0]; |
periph4_wr_o = io_wr_i; |
periph4_rd_o = io_rd_i; |
periph4_data_o = io_data_i; |
periph4_we_o = io_we_i; |
periph4_stb_o = io_stb_i; |
end |
// Peripheral 5 |
4'd 5 : |
begin |
periph5_addr_o = io_addr_i[7:0]; |
periph5_wr_o = io_wr_i; |
periph5_rd_o = io_rd_i; |
periph5_data_o = io_data_i; |
periph5_we_o = io_we_i; |
periph5_stb_o = io_stb_i; |
end |
// Peripheral 6 |
4'd 6 : |
begin |
periph6_addr_o = io_addr_i[7:0]; |
periph6_wr_o = io_wr_i; |
periph6_rd_o = io_rd_i; |
periph6_data_o = io_data_i; |
periph6_we_o = io_we_i; |
periph6_stb_o = io_stb_i; |
end |
// Peripheral 7 |
4'd 7 : |
begin |
periph7_addr_o = io_addr_i[7:0]; |
periph7_wr_o = io_wr_i; |
periph7_rd_o = io_rd_i; |
periph7_data_o = io_data_i; |
periph7_we_o = io_we_i; |
periph7_stb_o = io_stb_i; |
end |
|
default : |
266,67 → 205,42
//----------------------------------------------------------------- |
// Read Port |
//----------------------------------------------------------------- |
always @ * |
always @ (posedge clk_i or posedge rst_i) |
begin |
case (r_mem_sel) |
|
// Peripheral 0 |
4'd 0 : |
if (rst_i == 1'b1) |
begin |
io_data_o = periph0_data_i; |
io_data_o <= 32'b0; |
io_ack_o <= 1'b0; |
end |
// Peripheral 1 |
4'd 1 : |
else |
begin |
io_data_o = periph1_data_i; |
end |
// Peripheral 2 |
4'd 2 : |
begin |
io_data_o = periph2_data_i; |
end |
// Peripheral 3 |
4'd 3 : |
begin |
io_data_o = periph3_data_i; |
end |
// Peripheral 4 |
4'd 4 : |
begin |
io_data_o = periph4_data_i; |
end |
// Peripheral 5 |
4'd 5 : |
begin |
io_data_o = periph5_data_i; |
end |
// Peripheral 6 |
4'd 6 : |
begin |
io_data_o = periph6_data_i; |
end |
// Peripheral 7 |
4'd 7 : |
begin |
io_data_o = periph7_data_i; |
end |
if (io_stb_i) |
begin |
// Decode 4-bit peripheral select |
case (io_addr_i[11:8]) |
// Peripheral 0 |
4'd 0 : io_data_o <= periph0_data_i; |
// Peripheral 1 |
4'd 1 : io_data_o <= periph1_data_i; |
// Peripheral 2 |
4'd 2 : io_data_o <= periph2_data_i; |
// Peripheral 3 |
4'd 3 : io_data_o <= periph3_data_i; |
// Peripheral 4 |
4'd 4 : io_data_o <= periph4_data_i; |
// Peripheral 5 |
4'd 5 : io_data_o <= periph5_data_i; |
// Peripheral 6 |
4'd 6 : io_data_o <= periph6_data_i; |
// Peripheral 7 |
4'd 7 : io_data_o <= periph7_data_i; |
|
default : |
begin |
io_data_o = 32'h00000000; |
default : io_data_o <= 32'h00000000; |
endcase |
end |
|
io_ack_o <= io_stb_i; |
end |
endcase |
end |
|
//----------------------------------------------------------------- |
// Registered peripheral select |
//----------------------------------------------------------------- |
always @ (posedge clk_i or posedge rst_i) |
begin |
if (rst_i == 1'b1) |
r_mem_sel <= 4'h0; |
else |
r_mem_sel <= io_addr_i[11:8]; |
end |
|
endmodule |
/rtl/cpu/altor32_dcache.v
49,9 → 49,10
input [31:0] address_i /*verilator public*/, |
output [31:0] data_o /*verilator public*/, |
input [31:0] data_i /*verilator public*/, |
input rd_i /*verilator public*/, |
input [3:0] wr_i /*verilator public*/, |
output accept_o /*verilator public*/, |
input we_i /*verilator public*/, |
input stb_i /*verilator public*/, |
input [3:0] sel_i /*verilator public*/, |
output stall_o /*verilator public*/, |
output ack_o /*verilator public*/, |
|
// Output (Memory) |
58,10 → 59,12
output [31:0] mem_addr_o /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
output [31:0] mem_data_o /*verilator public*/, |
output mem_burst_o /*verilator public*/, |
output mem_rd_o /*verilator public*/, |
output [3:0] mem_wr_o /*verilator public*/, |
input mem_accept_i/*verilator public*/, |
output [2:0] mem_cti_o /*verilator public*/, |
output mem_cyc_o /*verilator public*/, |
output mem_stb_o /*verilator public*/, |
output mem_we_o /*verilator public*/, |
output [3:0] mem_sel_o /*verilator public*/, |
input mem_stall_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
); |
|
119,15 → 122,15
reg evict; |
wire done; |
|
reg [31:0] data_w; |
wire [31:0] data_r; |
reg data_rd; |
reg [3:0] data_wr; |
reg rd_single; |
reg [3:0] wr_single; |
|
reg req_rd; |
reg [3:0] req_wr; |
reg req_ack; |
reg [31:0] req_address; |
reg [31:0] req_data; |
|
reg req_flush; |
reg flush_single; |
157,9 → 160,8
assign cache_address = {tag_entry, muxed_address[CACHE_LINE_SIZE_WIDTH-1:2]}; |
|
assign data_o = (state == STATE_SINGLE_READY) ? data_r : cache_data_r; |
assign accept_o = (state == STATE_IDLE); |
assign stall_o = (state != STATE_IDLE) | req_flush; |
|
|
wire valid = tag_data_out[CACHE_TAG_VALID_BIT]; |
wire dirty = tag_data_out[CACHE_TAG_DIRTY_BIT]; |
|
166,8 → 168,11
// Access is cacheable? |
wire cacheable = ~muxed_address[ADDR_NO_CACHE_BIT] & ~muxed_address[ADDR_CACHE_BYPASS_BIT]; |
|
// Address matches cache tag |
wire addr_hit = (req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] == tag_data_out[13:0]); |
|
// Cache hit? |
wire hit = cacheable & valid & (muxed_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] == tag_data_out[13:0]) & (state == STATE_CHECK); |
wire hit = cacheable & valid & addr_hit & (state == STATE_CHECK); |
|
assign ack_o = ack | hit; |
|
175,43 → 180,514
assign line_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] = tag_data_out[13:0]; |
assign line_address[CACHE_LINE_SIZE_WIDTH-1:0] = {CACHE_LINE_SIZE_WIDTH{1'b0}}; |
|
|
//----------------------------------------------------------------- |
// Control logic |
// Next State Logic |
//----------------------------------------------------------------- |
reg [3:0] next_state_r; |
always @ * |
begin |
next_state_r = state; |
|
case (state) |
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Cache flush request |
if (flush_i | req_flush) |
next_state_r = STATE_FLUSH2; |
// Read (uncacheable) |
else if (stb_i & ~we_i & ~cacheable) |
next_state_r = STATE_SINGLE; |
// Read (cacheable) |
else if (stb_i & ~we_i) |
next_state_r = STATE_CHECK; |
// Write (uncacheable) |
else if (stb_i & we_i & ~cacheable) |
next_state_r = STATE_SINGLE; |
// Write (cacheable) |
else if (stb_i & we_i) |
next_state_r = STATE_WRITE; |
end |
//----------------------------------------- |
// WRITE - Wait for write-thru to complete |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Cache hit |
if (valid & addr_hit) |
next_state_r = STATE_WAIT2; |
// Cache dirty |
else if (valid & dirty) |
next_state_r = STATE_EVICTING; |
// Cache miss |
else |
next_state_r = STATE_UPDATE; |
end |
//----------------------------------------- |
// EVICTING - Evicting cache line |
//----------------------------------------- |
STATE_EVICTING: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Evict for read? |
if (req_rd) |
next_state_r = STATE_FETCH; |
// Evict for write |
else |
next_state_r = STATE_UPDATE; |
end |
end |
//----------------------------------------- |
// UPDATE - Update fetched cache line |
//----------------------------------------- |
STATE_UPDATE: |
begin |
// Data ready from memory? |
if (done) |
next_state_r = STATE_WAIT2; |
end |
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache hit |
if (valid & addr_hit) |
next_state_r = STATE_IDLE; |
// Cache dirty |
else if (valid & dirty) |
next_state_r = STATE_EVICTING; |
// Cache miss |
else |
next_state_r = STATE_FETCH; |
end |
//----------------------------------------- |
// FETCH_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_SINGLE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Single WRITE? |
if (~req_rd) |
next_state_r = STATE_SINGLE_READY; |
// Dirty? Write back |
else if (valid & dirty & addr_hit) |
next_state_r = STATE_FLUSH4; |
// Valid line, invalidate |
else if (valid & addr_hit) |
next_state_r = STATE_SINGLE_READY; |
else |
next_state_r = STATE_SINGLE_READY; |
end |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Cache line filled? |
if (done) |
next_state_r = STATE_WAIT; |
end |
//----------------------------------------- |
// WAIT - Wait cycle |
//----------------------------------------- |
STATE_WAIT : |
begin |
// Allow extra wait state to handle write & read collision |
next_state_r = STATE_WAIT2; |
end |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
begin |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// SINGLE_READY - Uncached access ready |
//----------------------------------------- |
STATE_SINGLE_READY : |
begin |
// Allow extra wait state to handle write & read collision |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// FLUSHx - Flush dirty lines & invalidate |
//----------------------------------------- |
STATE_FLUSH1 : |
begin |
if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}}) |
next_state_r = STATE_WAIT; |
else |
next_state_r = STATE_FLUSH2; |
end |
//----------------------------------------- |
// FLUSH2 - Wait state |
//----------------------------------------- |
STATE_FLUSH2 : |
begin |
// Allow a cycle to read line state |
next_state_r = STATE_FLUSH3; |
end |
//----------------------------------------- |
// FLUSH3 - Check if line dirty & flush |
//----------------------------------------- |
STATE_FLUSH3 : |
begin |
// Dirty line? Evict line first |
if (dirty) |
next_state_r = STATE_FLUSH4; |
// Not dirty? Just invalidate |
else |
begin |
if (flush_single) |
next_state_r = STATE_WAIT; |
else |
next_state_r = STATE_FLUSH1; |
end |
end |
//----------------------------------------- |
// FLUSH4 - Wait for line flush to complete |
//----------------------------------------- |
STATE_FLUSH4 : |
begin |
// Cache line filled? |
if (done) |
begin |
if (flush_single) |
next_state_r = STATE_SINGLE_READY; |
else |
next_state_r = STATE_FLUSH1; |
end |
end |
|
default: |
; |
endcase |
end |
|
// Update state |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
state <= STATE_IDLE; |
else |
state <= next_state_r; |
end |
|
//----------------------------------------------------------------- |
// Tag Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
data_w <= 32'h00000000; |
data_wr <= 4'h0; |
data_rd <= 1'b0; |
tag_data_in <= 16'b0; |
tag_wr <= 1'b0; |
end |
else |
begin |
tag_wr <= 1'b0; |
|
case (state) |
//----------------------------------------- |
// WRITE - Wait for write-thru to complete |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Cache hit |
if (valid & addr_hit) |
begin |
// Mark line as dirty |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1; |
tag_wr <= 1'b1; |
end |
// Cache miss / cache line doesn't require write back |
else if (~valid | ~dirty) |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, 1'b1, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// EVICTING - Evicting cache line |
//----------------------------------------- |
STATE_EVICTING: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Update tag memory with this new line's details |
tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// UPDATE - Update fetched cache line |
//----------------------------------------- |
STATE_UPDATE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Mark line as dirty |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache hit |
if (valid & addr_hit) |
begin |
|
end |
// Cache miss / cache line doesn't require write back |
else if (~valid | ~dirty) |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// FETCH_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_SINGLE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Single WRITE? |
if (~req_rd) |
begin |
// Invalidate cached version |
if (valid & addr_hit) |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
end |
// Valid line (not dirty), just invalidate |
else if (valid & ~dirty & addr_hit) |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
end |
end |
|
//----------------------------------------- |
// FLUSH3 - Check if line dirty & flush |
//----------------------------------------- |
STATE_FLUSH3 : |
begin |
// Not dirty? Just invalidate |
if (~dirty) |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// FLUSH4 - Wait for line flush to complete |
//----------------------------------------- |
STATE_FLUSH4 : |
begin |
// Cache line filled? |
if (done) |
begin |
// Invalidate line |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Register requests |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
req_address <= 32'h00000000; |
req_data <= 32'h00000000; |
req_ack <= 1'b0; |
req_wr <= 4'h0; |
req_rd <= 1'b0; |
tag_wr <= 1'b0; |
req_flush <= 1'b0; |
end |
else |
begin |
if (flush_i) |
req_flush <= 1'b1; |
|
case (state) |
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Cache flush request |
if (flush_i | req_flush) |
begin |
// Set to first line address |
req_address <= 32'h00000000; |
req_flush <= 1'b0; |
req_ack <= 1'b0; |
end |
// Read (uncacheable) |
else if (stb_i & ~we_i & ~cacheable) |
begin |
// Start read single from memory |
req_address <= address_i; |
req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0; |
req_rd <= 1'b1; |
req_wr <= 4'b0; |
req_ack <= 1'b1; |
end |
// Read (cacheable) |
else if (stb_i & ~we_i) |
begin |
req_address <= address_i; |
req_rd <= 1'b1; |
req_wr <= 4'b0; |
req_ack <= 1'b1; |
end |
// Write (uncacheable) |
else if (stb_i & we_i & ~cacheable) |
begin |
// Perform write single |
req_address <= address_i; |
req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0; |
req_data <= data_i; |
req_wr <= sel_i; |
req_rd <= 1'b0; |
req_ack <= 1'b1; |
end |
// Write (cacheable) |
else if (stb_i & we_i) |
begin |
req_address <= address_i; |
req_data <= data_i; |
req_wr <= sel_i; |
req_rd <= 1'b0; |
req_ack <= 1'b0; |
end |
end |
//----------------------------------------- |
// FLUSHx - Flush dirty lines & invalidate |
//----------------------------------------- |
STATE_FLUSH1 : |
begin |
if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}}) |
begin |
req_ack <= 1'b0; |
end |
else |
begin |
// Increment flush line address |
req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] <= |
req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] + 1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Cache Data Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
cache_data_w <= 32'h00000000; |
cache_wr <= 4'b0; |
end |
else |
begin |
cache_wr <= 4'b0; |
|
case (state) |
//----------------------------------------- |
// WRITE - Wait for write-thru to complete |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Cache hit |
if (valid & addr_hit) |
begin |
// Update line already in cache |
cache_data_w <= req_data; |
cache_wr <= req_wr; |
end |
end |
//----------------------------------------- |
// UPDATE - Update fetched cache line |
//----------------------------------------- |
STATE_UPDATE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Update line already in cache |
cache_data_w <= req_data; |
cache_wr <= req_wr; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Control |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
wr_single <= 4'h0; |
rd_single <= 1'b0; |
flush_single <= 1'b0; |
fill <= 1'b0; |
evict <= 1'b0; |
cache_data_w <= 32'h00000000; |
cache_wr <= 4'b0; |
ack <= 1'b0; |
state <= STATE_IDLE; |
end |
else |
begin |
ack <= 1'b0; |
tag_wr <= 1'b0; |
fill <= 1'b0; |
evict <= 1'b0; |
cache_wr <= 4'b0; |
data_wr <= 4'b0; |
data_rd <= 1'b0; |
wr_single <= 4'b0; |
rd_single <= 1'b0; |
|
if (flush_i) |
req_flush <= 1'b1; |
|
case (state) |
|
//----------------------------------------- |
218,65 → 694,25
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
begin |
// Cache flush request |
if (flush_i | req_flush) |
begin |
// Set to first line address |
flush_single<= 1'b0; |
end |
// Read (uncacheable) |
if (rd_i & ~cacheable) |
else if (stb_i & ~we_i & ~cacheable) |
begin |
// Start read single from memory |
req_address <= address_i; |
req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0; |
data_rd <= 1'b1; |
req_rd <= 1'b1; |
req_wr <= 4'b0; |
req_ack <= 1'b1; |
state <= STATE_SINGLE; |
end |
// Read (cacheable) |
else if (rd_i) |
begin |
req_address <= address_i; |
req_rd <= 1'b1; |
req_wr <= 4'b0; |
req_ack <= 1'b1; |
state <= STATE_CHECK; |
end |
rd_single <= 1'b1; |
end |
// Write (uncacheable) |
else if (wr_i != 4'b0000 & ~cacheable) |
else if (stb_i & we_i & ~cacheable) |
begin |
// Perform write single |
req_address <= address_i; |
req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0; |
data_w <= data_i; |
data_wr <= wr_i; |
req_wr <= wr_i; |
req_rd <= 1'b0; |
req_ack <= 1'b1; |
state <= STATE_SINGLE; |
end |
// Write (cacheable) |
else if (wr_i != 4'b0000) |
begin |
req_address <= address_i; |
data_w <= data_i; |
req_wr <= wr_i; |
req_rd <= 1'b0; |
req_ack <= 1'b0; |
|
// Early ACK |
ack <= 1'b1; |
|
state <= STATE_WRITE; |
end |
// Cache flush request |
else if (flush_i | req_flush) |
begin |
// Set to first line address |
req_address <= 32'h00000000; |
req_flush <= 1'b0; |
req_ack <= 1'b0; |
flush_single<= 1'b0; |
state <= STATE_FLUSH2; |
end |
wr_single <= sel_i; |
end |
end |
//----------------------------------------- |
// WRITE - Wait for write-thru to complete |
284,19 → 720,9
STATE_WRITE : |
begin |
// Cache hit |
if (valid && |
(req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] == tag_data_out[13:0])) |
if (valid & addr_hit) |
begin |
// Update line already in cache |
cache_data_w <= data_w; |
cache_wr <= req_wr; |
|
// Mark line as dirty |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1; |
tag_wr <= 1'b1; |
|
state <= STATE_WAIT2; |
end |
// Cache dirty |
else if (valid & dirty) |
303,18 → 729,12
begin |
// Evict cache line |
evict <= 1'b1; |
state <= STATE_EVICTING; |
end |
// Cache miss |
else |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, 1'b1, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
|
// Fill cache line |
fill <= 1'b1; |
state <= STATE_UPDATE; |
end |
end |
//----------------------------------------- |
325,51 → 745,19
// Data ready from memory? |
if (done) |
begin |
// Update tag memory with this new line's details |
tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
|
// Fill cache line |
fill <= 1'b1; |
|
// Evict for read? |
if (req_rd) |
state <= STATE_FETCH; |
// Evict for write |
else |
state <= STATE_UPDATE; |
end |
end |
end |
//----------------------------------------- |
// UPDATE - Update fetched cache line |
//----------------------------------------- |
STATE_UPDATE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Update line already in cache |
cache_data_w <= data_w; |
cache_wr <= req_wr; |
|
// Mark line as dirty |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1; |
tag_wr <= 1'b1; |
|
state <= STATE_WAIT2; |
end |
end |
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache hit |
if (valid && |
(req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] == tag_data_out[13:0])) |
if (valid & addr_hit) |
begin |
state <= STATE_IDLE; |
|
end |
// Cache dirty |
else if (valid & dirty) |
376,18 → 764,12
begin |
// Evict cache line |
evict <= 1'b1; |
state <= STATE_EVICTING; |
end |
// Cache miss |
else |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
|
// Fill cache line |
fill <= 1'b1; |
state <= STATE_FETCH; |
end |
end |
//----------------------------------------- |
401,95 → 783,18
// Single WRITE? |
if (~req_rd) |
begin |
state <= STATE_SINGLE_READY; |
ack <= req_ack; |
|
end |
// Dirty? Write back |
else if (valid & dirty) |
else if (valid & dirty & addr_hit) |
begin |
// Evict cache line |
evict <= 1'b1; |
flush_single<= 1'b1; |
state <= STATE_FLUSH4; |
end |
// Valid line, invalidate |
else if (valid) |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
|
state <= STATE_SINGLE_READY; |
ack <= req_ack; |
end |
else |
begin |
state <= STATE_SINGLE_READY; |
ack <= req_ack; |
end |
end |
end |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Cache line filled? |
if (done) |
state <= STATE_WAIT; |
end |
//----------------------------------------- |
// WAIT - Wait cycle |
//----------------------------------------- |
STATE_WAIT : |
begin |
// Allow extra wait state to handle write & read collision |
state <= STATE_WAIT2; |
end |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
begin |
state <= STATE_IDLE; |
ack <= req_ack; |
end |
//----------------------------------------- |
// SINGLE_READY - Uncached access ready |
//----------------------------------------- |
STATE_SINGLE_READY : |
begin |
// Allow extra wait state to handle write & read collision |
state <= STATE_IDLE; |
end |
//----------------------------------------- |
// FLUSHx - Flush dirty lines & invalidate |
//----------------------------------------- |
STATE_FLUSH1 : |
begin |
if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}}) |
begin |
req_ack <= 1'b0; |
state <= STATE_WAIT; |
end |
else |
begin |
// Increment flush line address |
req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] <= |
req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] + 1; |
|
state <= STATE_FLUSH2; |
end |
end |
//----------------------------------------- |
// FLUSH2 - Wait state |
//----------------------------------------- |
STATE_FLUSH2 : |
begin |
// Allow a cycle to read line state |
state <= STATE_FLUSH3; |
end |
//----------------------------------------- |
// FLUSH3 - Check if line dirty & flush |
//----------------------------------------- |
STATE_FLUSH3 : |
499,47 → 804,77
begin |
// Evict cache line |
evict <= 1'b1; |
state <= STATE_FLUSH4; |
end |
// Not dirty? Just invalidate |
else |
begin |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
end |
default: |
; |
endcase |
end |
end |
|
if (flush_single) |
state <= STATE_WAIT; |
else |
state <= STATE_FLUSH1; |
end |
end |
//----------------------------------------- |
// FLUSH4 - Wait for line flush to complete |
//----------------------------------------- |
STATE_FLUSH4 : |
//----------------------------------------------------------------- |
// ACK |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
ack <= 1'b0; |
else |
begin |
ack <= 1'b0; |
|
case (state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Write (cacheable), early acknowledge |
if (~(flush_i | req_flush) & stb_i & we_i & cacheable) |
ack <= 1'b1; |
end |
//----------------------------------------- |
// FETCH_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_SINGLE: |
begin |
// Data ready from memory? |
if (done) |
begin |
// Cache line filled? |
if (done) |
// Single WRITE? |
if (~req_rd) |
ack <= req_ack; |
// Dirty? Write back |
else if (valid & dirty & addr_hit) |
begin |
// Invalidate line |
tag_data_in <= tag_data_out; |
tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0; |
tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b0; |
tag_wr <= 1'b1; |
|
if (flush_single) |
begin |
state <= STATE_SINGLE_READY; |
ack <= req_ack; |
end |
else |
state <= STATE_FLUSH1; |
end |
end |
default: |
; |
endcase |
// Valid line, invalidate |
else if (valid & addr_hit) |
ack <= req_ack; |
else |
ack <= req_ack; |
end |
end |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
begin |
ack <= req_ack; |
end |
//----------------------------------------- |
// FLUSH4 - Wait for line flush to complete |
//----------------------------------------- |
STATE_FLUSH4 : |
begin |
if (done & flush_single) |
ack <= req_ack; |
end |
default: |
; |
endcase |
end |
end |
|
559,13 → 894,13
|
// Cache interface |
.address_i(muxed_address), |
.data_i(data_w), |
.data_i(req_data), |
.data_o(data_r), |
.fill_i(fill), |
.evict_i(evict), |
.evict_addr_i(line_address), |
.rd_single_i(data_rd), |
.wr_single_i(data_wr), |
.rd_single_i(rd_single), |
.wr_single_i(wr_single), |
.done_o(done), |
|
// Cache memory (fill/evict) |
578,10 → 913,12
.mem_addr_o(mem_addr_o), |
.mem_data_i(mem_data_i), |
.mem_data_o(mem_data_o), |
.mem_burst_o(mem_burst_o), |
.mem_rd_o(mem_rd_o), |
.mem_wr_o(mem_wr_o), |
.mem_accept_i(mem_accept_i), |
.mem_cti_o(mem_cti_o), |
.mem_cyc_o(mem_cyc_o), |
.mem_stb_o(mem_stb_o), |
.mem_we_o(mem_we_o), |
.mem_sel_o(mem_sel_o), |
.mem_stall_i(mem_stall_i), |
.mem_ack_i(mem_ack_i) |
); |
|
/rtl/cpu/altor32_noicache.v
54,13 → 54,14
output [31:0] instruction_o /*verilator public*/, |
output valid_o /*verilator public*/, |
|
// Memory interface (slave) |
output reg [31:0] mem_addr_o /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
output reg mem_burst_o /*verilator public*/, |
output reg mem_rd_o /*verilator public*/, |
input mem_accept_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
// Memory interface |
output reg [31:0] wbm_addr_o /*verilator public*/, |
input [31:0] wbm_dat_i /*verilator public*/, |
output [2:0] wbm_cti_o /*verilator public*/, |
output reg wbm_cyc_o /*verilator public*/, |
output reg wbm_stb_o /*verilator public*/, |
input wbm_stall_i/*verilator public*/, |
input wbm_ack_i/*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
70,11 → 71,13
// Current state |
parameter STATE_CHECK = 0; |
parameter STATE_FETCH = 1; |
reg [1:0] state; |
reg state; |
|
assign valid_o = mem_ack_i; |
assign instruction_o = mem_data_i; |
reg ignore_resp; |
|
assign valid_o = wbm_ack_i & ~ignore_resp & ~rd_i; |
assign instruction_o = wbm_dat_i; |
|
//----------------------------------------------------------------- |
// Control logic |
//----------------------------------------------------------------- |
82,16 → 85,17
begin |
if (rst_i == 1'b1) |
begin |
mem_addr_o <= 32'h00000000; |
mem_rd_o <= 1'b0; |
mem_burst_o <= 1'b0; |
wbm_addr_o <= 32'h00000000; |
wbm_stb_o <= 1'b0; |
wbm_cyc_o <= 1'b0; |
ignore_resp <= 1'b0; |
state <= STATE_CHECK; |
end |
else |
begin |
|
if (mem_accept_i) |
mem_rd_o <= 1'b0; |
if (~wbm_stall_i) |
wbm_stb_o <= 1'b0; |
|
case (state) |
|
101,9 → 105,10
STATE_CHECK : |
begin |
// Start fetch from memory |
mem_addr_o <= pc_i; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b0; |
wbm_addr_o <= pc_i; |
wbm_stb_o <= 1'b1; |
wbm_cyc_o <= 1'b1; |
ignore_resp <= 1'b0; |
state <= STATE_FETCH; |
end |
//----------------------------------------- |
111,9 → 116,16
//----------------------------------------- |
STATE_FETCH : |
begin |
// Read whilst waiting for previous response? |
if (rd_i) |
ignore_resp <= 1'b1; |
|
// Data ready from memory? |
if (mem_ack_i) |
state <= STATE_CHECK; |
if (wbm_ack_i) |
begin |
wbm_cyc_o <= 1'b0; |
state <= STATE_CHECK; |
end |
end |
|
default: |
122,5 → 134,7
end |
end |
|
assign wbm_cti_o = 3'b111; |
|
endmodule |
|
/rtl/cpu/altor32_icache.v
43,7 → 43,7
//----------------------------------------------------------------- |
// Module - Instruction Cache |
//----------------------------------------------------------------- |
module altor32_icache |
module altor32_icache |
( |
input clk_i /*verilator public*/, |
input rst_i /*verilator public*/, |
59,13 → 59,14
output miss_o /*verilator public*/, |
output busy_o /*verilator public*/, |
|
// Memory interface (slave) |
output reg [31:0] mem_addr_o /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
output reg mem_burst_o /*verilator public*/, |
output reg mem_rd_o /*verilator public*/, |
input mem_accept_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
// Memory interface |
output reg [31:0] wbm_addr_o /*verilator public*/, |
input [31:0] wbm_dat_i /*verilator public*/, |
output reg [2:0] wbm_cti_o /*verilator public*/, |
output reg wbm_cyc_o /*verilator public*/, |
output reg wbm_stb_o /*verilator public*/, |
input wbm_stall_i/*verilator public*/, |
input wbm_ack_i/*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
100,28 → 101,36
//----------------------------------------------------------------- |
// Registers / Wires |
//----------------------------------------------------------------- |
|
// Tag read / write data |
wire [CACHE_TAG_WIDTH-1:0] tag_data_out; |
reg [CACHE_TAG_WIDTH-1:0] tag_data_in; |
reg tag_wr; |
|
// Tag address |
wire [CACHE_LINE_ADDR_WIDTH-1:0] tag_entry; |
|
// Data memory read / write |
wire [CACHE_DWIDTH-1:0] cache_address_rd; |
|
reg [CACHE_DWIDTH-1:0] cache_address_wr; |
reg [31:0] cache_data_w; |
reg [31:0] cache_data_in; |
reg cache_wr; |
|
reg [CACHE_LINE_SIZE_WIDTH-3:0] fetch_word; |
// Word currently being fetched within a line |
reg [CACHE_LINE_SIZE_WIDTH-3:0] mem_fetch_word; |
reg [CACHE_LINE_SIZE_WIDTH-3:0] mem_resp_idx; |
|
// Current / Miss PC |
reg [31:0] last_pc; |
reg [31:0] miss_pc; |
|
reg initial_fetch; |
// Flush state |
reg flush_req; |
|
reg [CACHE_LINE_ADDR_WIDTH-1:0] flush_addr; |
reg flush_wr; |
|
// Other state |
reg initial_fetch; |
reg read_while_busy; |
|
// Current state |
130,38 → 139,259
parameter STATE_WAIT = 2; |
parameter STATE_WAIT2 = 3; |
parameter STATE_FLUSH = 4; |
reg [3:0] state; |
reg [3:0] state; |
|
assign tag_entry = (state != STATE_CHECK) ? miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] : pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH]; |
assign cache_address_rd = pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:2]; |
// Tag address from input PC or flopped version of it |
assign tag_entry = (state != STATE_CHECK) ? |
miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] : |
pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH]; |
|
assign miss_o = (!tag_data_out[CACHE_TAG_VALID_BIT] || (last_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] != tag_data_out[14:0])) ? 1'b1: 1'b0; |
// Cache read address |
assign cache_address_rd = pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:2]; |
|
// Cache miss output if requested PC is not in the tag memory |
assign miss_o = (!tag_data_out[CACHE_TAG_VALID_BIT] || |
(last_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] != tag_data_out[14:0])) ? 1'b1: 1'b0; |
|
// Cache output valid |
assign valid_o = !miss_o && !busy_o; |
|
// Stall the CPU if cache state machine is not idle! |
assign busy_o = (state == STATE_CHECK & ~read_while_busy) ? 1'b0 : 1'b1; |
|
// Final word to fetch from memory |
wire mem_fetch_final_word = (mem_fetch_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}); |
|
// Flushing: Last line to flush |
wire flush_final_line = (flush_addr == {CACHE_LINE_ADDR_WIDTH{1'b0}}); |
|
// Is this a cache miss? |
wire cache_miss = (miss_o && // Tag lookup failed |
!initial_fetch && // NOT initial fetch after reset |
!rd_i && // NOT new read request cycle |
!read_while_busy && // NOT pending read whilst busy |
!flush_req && // NOT flush request |
!invalidate_i); |
|
//----------------------------------------------------------------- |
// Control logic |
// Next State Logic |
//----------------------------------------------------------------- |
reg [CACHE_LINE_SIZE_WIDTH-3:0] v_line_word; |
reg [3:0] next_state_r; |
always @ * |
begin |
next_state_r = state; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache flush request pending? |
if (flush_req || invalidate_i) |
next_state_r = STATE_FLUSH; |
// Cache miss (& new read request not pending) |
else if (cache_miss) |
next_state_r = STATE_FETCH; |
// Cache hit (or new read request) |
else |
next_state_r = STATE_CHECK; |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Line fetch complete? |
if (mem_resp_idx == {CACHE_LINE_SIZE_WIDTH-2{1'b1}} && wbm_ack_i) |
next_state_r = STATE_WAIT; |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
if (flush_final_line) |
next_state_r = STATE_FETCH; |
else |
next_state_r = STATE_FLUSH; |
end |
//----------------------------------------- |
// WAIT - Wait cycle |
//----------------------------------------- |
STATE_WAIT : |
// Allow extra wait state to handle write & read collision |
next_state_r = STATE_WAIT2; |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
next_state_r = STATE_CHECK; |
default: |
; |
endcase |
end |
|
// Update state |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
state <= STATE_CHECK; |
else |
state <= next_state_r; |
end |
|
|
//----------------------------------------------------------------- |
// Check for cache misses |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
mem_addr_o <= 32'h00000000; |
mem_rd_o <= 1'b0; |
mem_burst_o <= 1'b0; |
tag_wr <= 1'b0; |
cache_address_wr<= {CACHE_DWIDTH{1'b0}}; |
cache_data_w <= 32'h00000000; |
cache_wr <= 1'b0; |
miss_pc <= BOOT_VECTOR + `VECTOR_RESET; |
last_pc <= 32'h00000000; |
state <= STATE_CHECK; |
last_pc <= 32'h00000000; |
initial_fetch <= 1'b1; |
read_while_busy <= 1'b0; |
end |
else |
begin |
initial_fetch <= 1'b0; |
last_pc <= pc_i; |
|
// New request whilst cache busy? |
if (rd_i) |
read_while_busy <= 1'b1; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
begin |
read_while_busy <= 1'b0; |
|
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache miss at 0x%x (last=%x, current=%x)", miss_pc, last_pc, pc_i); |
`endif |
end |
// Cache hit (or new read request) |
else |
begin |
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache hit at PC=%x (current=%x)", last_pc, pc_i); |
if (read_while_busy) |
$display("Fetch: Read request whilst busy PC=%x (current=%x)", last_pc, pc_i); |
`endif |
// Store fetch PC |
miss_pc <= pc_i; |
read_while_busy <= 1'b0; |
end |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
// Last line, clear pending reads whilst busy |
if (flush_final_line) |
read_while_busy <= 1'b0; |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Cache Tag Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
tag_data_in <= {CACHE_TAG_WIDTH{1'b0}}; |
tag_wr <= 1'b0; |
end |
else |
begin |
tag_wr <= 1'b0; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, miss_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
if (flush_final_line) |
begin |
// Update tag memory with this line's details |
tag_data_in <= {1'b1, pc_i[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Cache Data Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
cache_address_wr<= {CACHE_DWIDTH{1'b0}}; |
cache_data_in <= 32'h00000000; |
cache_wr <= 1'b0; |
end |
else |
begin |
cache_wr <= 1'b0; |
|
// FETCH - Fetch row from memory |
if (state == STATE_FETCH) |
begin |
// Data ready from memory? |
if (wbm_ack_i) |
begin |
// Write data into cache |
cache_address_wr <= {miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH], mem_resp_idx}; |
cache_data_in <= wbm_dat_i; |
cache_wr <= 1'b1; |
end |
end |
end |
end |
|
//----------------------------------------------------------------- |
// Flush Logic |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b0}}; |
flush_wr <= 1'b0; |
flush_req <= 1'b0; |
168,176 → 398,236
end |
else |
begin |
|
if (mem_accept_i) |
mem_rd_o <= 1'b0; |
tag_wr <= 1'b0; |
cache_wr <= 1'b0; |
initial_fetch <= 1'b0; |
flush_wr <= 1'b0; |
last_pc <= pc_i; |
|
// Latch invalidate request even if can't be actioned now... |
if (invalidate_i) |
flush_req <= 1'b1; |
|
// New request whilst cache busy? |
if (rd_i) |
read_while_busy <= 1'b1; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache flush request pending? |
if (flush_req || invalidate_i) |
begin |
// Cache flush request pending? |
if (flush_req || invalidate_i) |
begin |
flush_req <= 1'b0; |
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b1}}; |
flush_wr <= 1'b1; |
state <= STATE_FLUSH; |
flush_req <= 1'b0; |
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b1}}; |
flush_wr <= 1'b1; |
|
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache flush request"); |
`endif |
end |
// Cache miss (& new read request not pending) |
else if ((miss_o && !initial_fetch) && !rd_i && !read_while_busy) |
begin |
read_while_busy <= 1'b0; |
$display("Fetch: Cache flush request"); |
`endif |
end |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
if (~flush_final_line) |
begin |
flush_addr <= flush_addr - 1; |
flush_wr <= 1'b1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
//----------------------------------------------------------------- |
// External Mem Access |
//----------------------------------------------------------------- |
|
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache miss at 0x%x (last=%x, current=%x)", miss_pc, last_pc, pc_i); |
`endif |
|
// Start fetch from memory |
mem_addr_o <= {miss_pc[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b1; |
state <= STATE_FETCH; |
|
// Update tag memory with this line's details |
tag_data_in <= {1'b1, miss_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
end |
// Cache hit (or new read request) |
else |
begin |
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Cache hit at PC=%x (current=%x)", last_pc, pc_i); |
if (read_while_busy) |
$display("Fetch: Read request whilst busy PC=%x (current=%x)", last_pc, pc_i); |
`endif |
// Next fetch address |
wire [CACHE_LINE_SIZE_WIDTH-3:0] mem_next_word = mem_fetch_word + 1; |
|
// Store fetch PC |
miss_pc <= pc_i; |
state <= STATE_CHECK; |
read_while_busy <= 1'b0; |
end |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
// Last word to fetch |
wire mem_resp_idx_word = (mem_fetch_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1)); |
|
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
wbm_addr_o <= 32'h00000000; |
wbm_cti_o <= 3'b0; |
wbm_stb_o <= 1'b0; |
|
mem_fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
else |
begin |
if (~wbm_stall_i) |
wbm_stb_o <= 1'b0; |
|
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
begin |
// Data ready from memory? |
if (mem_ack_i) |
begin |
// Write data into cache |
cache_address_wr<= {miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH], fetch_word}; |
cache_data_w <= mem_data_i; |
cache_wr <= 1'b1; |
// Start fetch from memory |
wbm_addr_o <= {miss_pc[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
|
// Line fetch complete? |
if (fetch_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
begin |
state <= STATE_WAIT; |
end |
// Fetch next word for line |
else |
begin |
v_line_word = fetch_word + 1'b1; |
fetch_word <= v_line_word; |
|
mem_addr_o <= {mem_addr_o[31:CACHE_LINE_SIZE_WIDTH], v_line_word, 2'b00}; |
mem_rd_o <= 1'b1; |
|
if (fetch_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1)) |
begin |
mem_burst_o <= 1'b0; |
end |
end |
end |
// Incrementing linear burst |
wbm_cti_o <= 3'b010; |
|
// Start of cycle |
wbm_stb_o <= 1'b1; |
|
mem_fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
if (flush_addr == {CACHE_LINE_ADDR_WIDTH{1'b0}}) |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Command accepted |
if (~wbm_stall_i) |
begin |
// Fetch next word for line |
if (!mem_fetch_final_word) |
begin |
// Fetch current PC line again |
mem_addr_o <= {pc_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b1; |
state <= STATE_FETCH; |
|
// Update tag memory with this line's details |
tag_data_in <= {1'b1, pc_i[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]}; |
tag_wr <= 1'b1; |
wbm_addr_o <= {wbm_addr_o[31:CACHE_LINE_SIZE_WIDTH], mem_next_word, 2'b00}; |
|
// Final word to read? |
if (mem_resp_idx_word) |
wbm_cti_o <= 3'b111; |
|
// Start of line |
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
mem_fetch_word <= mem_next_word; |
|
// Clear pending reads whilst busy |
read_while_busy <= 1'b0; |
end |
else |
begin |
flush_addr <= flush_addr - 1; |
flush_wr <= 1'b1; |
state <= STATE_FLUSH; |
end |
end |
//----------------------------------------- |
// WAIT - Wait cycle |
//----------------------------------------- |
STATE_WAIT : |
begin |
// Allow extra wait state to handle write & read collision |
state <= STATE_WAIT2; |
end |
//----------------------------------------- |
// WAIT2 - Wait cycle |
//----------------------------------------- |
STATE_WAIT2 : |
begin |
`ifdef CONF_CORE_DEBUG |
$display("Fetch: Filled line containing PC=%x", miss_pc); |
`endif |
state <= STATE_CHECK; |
end |
|
|
default: |
; |
endcase |
// Still fetching... |
wbm_stb_o <= 1'b1; |
end |
end |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
// Fetch current PC line again |
if (flush_final_line) |
begin |
wbm_addr_o <= {pc_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
|
// Incrementing linear burst |
wbm_cti_o <= 3'b010; |
|
// Start of cycle |
wbm_stb_o <= 1'b1; |
|
// Start of line |
mem_fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
end |
default: |
; |
endcase |
end |
end |
|
// Stall the CPU if cache state machine is not idle! |
assign busy_o = (state == STATE_CHECK & ~read_while_busy) ? 1'b0 : 1'b1; |
//----------------------------------------------------------------- |
// CYC_O |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
wbm_cyc_o <= 1'b0; |
else |
begin |
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
wbm_cyc_o <= 1'b1; |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
// Fetch current PC line again |
if (flush_final_line) |
wbm_cyc_o <= 1'b1; |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Last response? |
if (wbm_ack_i && (mem_resp_idx == {CACHE_LINE_SIZE_WIDTH-2{1'b1}})) |
wbm_cyc_o <= 1'b0; |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Instantiation |
// Memory response counter |
//----------------------------------------------------------------- |
|
// Tag memory |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
mem_resp_idx <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
else |
begin |
case (state) |
|
//----------------------------------------- |
// CHECK - check cache for hit or miss |
//----------------------------------------- |
STATE_CHECK : |
begin |
// Cache miss (& new read request not pending) |
if (cache_miss) |
mem_resp_idx <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
//----------------------------------------- |
// FLUSH - Invalidate tag memory |
//----------------------------------------- |
STATE_FLUSH : |
begin |
// Fetch current PC line again |
if (flush_final_line) |
mem_resp_idx <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
end |
//----------------------------------------- |
// FETCH - Fetch row from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Response |
if (wbm_ack_i) |
mem_resp_idx <= mem_resp_idx + 1; |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Tag memory |
//----------------------------------------------------------------- |
altor32_ram_dp |
#( |
.WIDTH(CACHE_TAG_WIDTH), |
345,6 → 635,7
) |
u1_tag_mem |
( |
// Tag read/write port |
.aclk_i(clk_i), |
.adat_o(tag_data_out), |
.adat_i(tag_data_in), |
351,6 → 642,7
.aadr_i(tag_entry), |
.awr_i(tag_wr), |
|
// Tag invalidate port |
.bclk_i(clk_i), |
.badr_i(flush_addr), |
.bdat_o(/*open*/), |
357,8 → 649,10
.bdat_i({CACHE_TAG_WIDTH{1'b0}}), |
.bwr_i(flush_wr) |
); |
|
|
//----------------------------------------------------------------- |
// Data memory |
//----------------------------------------------------------------- |
altor32_ram_dp |
#( |
.WIDTH(32), |
366,6 → 660,7
) |
u2_data_mem |
( |
// Data read port |
.aclk_i(clk_i), |
.aadr_i(cache_address_rd), |
.adat_o(instruction_o), |
372,10 → 667,11
.adat_i(32'h00), |
.awr_i(1'b0), |
|
// Data write port |
.bclk_i(clk_i), |
.badr_i(cache_address_wr), |
.bdat_o(/*open*/), |
.bdat_i(cache_data_w), |
.bdat_i(cache_data_in), |
.bwr_i(cache_wr) |
); |
|
/rtl/cpu/altor32.v
41,7 → 41,7
`include "altor32_defs.v" |
|
//----------------------------------------------------------------- |
// Module - AltOR32 CPU |
// Module - AltOR32 CPU (Pipelined Wishbone Interfaces) |
//----------------------------------------------------------------- |
module cpu |
( |
56,21 → 56,24
|
// Instruction memory |
output [31:0] imem_addr_o /*verilator public*/, |
output imem_rd_o /*verilator public*/, |
output imem_burst_o /*verilator public*/, |
input [31:0] imem_data_in_i /*verilator public*/, |
input imem_accept_i /*verilator public*/, |
input imem_ack_i /*verilator public*/, |
input [31:0] imem_dat_i /*verilator public*/, |
output [2:0] imem_cti_o /*verilator public*/, |
output imem_cyc_o /*verilator public*/, |
output imem_stb_o /*verilator public*/, |
input imem_stall_i/*verilator public*/, |
input imem_ack_i/*verilator public*/, |
|
// Data memory |
output [31:0] dmem_addr_o /*verilator public*/, |
output [31:0] dmem_data_out_o /*verilator public*/, |
input [31:0] dmem_data_in_i /*verilator public*/, |
output [3:0] dmem_wr_o /*verilator public*/, |
output dmem_rd_o /*verilator public*/, |
output dmem_burst_o /*verilator public*/, |
input dmem_accept_i /*verilator public*/, |
input dmem_ack_i /*verilator public*/ |
output [31:0] dmem_dat_o /*verilator public*/, |
input [31:0] dmem_dat_i /*verilator public*/, |
output [3:0] dmem_sel_o /*verilator public*/, |
output [2:0] dmem_cti_o /*verilator public*/, |
output dmem_cyc_o /*verilator public*/, |
output dmem_we_o /*verilator public*/, |
output dmem_stb_o /*verilator public*/, |
input dmem_stall_i/*verilator public*/, |
input dmem_ack_i/*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
140,10 → 143,12
wire [31:0] dcache_addr; |
wire [31:0] dcache_data_o; |
wire [31:0] dcache_data_i; |
wire [3:0] dcache_wr; |
wire dcache_rd; |
wire [3:0] dcache_sel; |
wire dcache_we; |
wire dcache_stb; |
wire dcache_cyc; |
wire dcache_ack; |
wire dcache_accept; |
wire dcache_stall; |
wire dcache_flush; |
|
//----------------------------------------------------------------- |
176,16 → 181,17
.busy_o(icache_busy), |
|
// Instruction memory |
.mem_addr_o(imem_addr_o), |
.mem_data_i(imem_data_in_i), |
.mem_burst_o(imem_burst_o), |
.mem_rd_o(imem_rd_o), |
.mem_accept_i(imem_accept_i), |
.mem_ack_i(imem_ack_i) |
.wbm_addr_o(imem_addr_o), |
.wbm_dat_i(imem_dat_i), |
.wbm_cti_o(imem_cti_o), |
.wbm_cyc_o(imem_cyc_o), |
.wbm_stb_o(imem_stb_o), |
.wbm_stall_i(imem_stall_i), |
.wbm_ack_i(imem_ack_i) |
); |
end |
else |
begin |
begin : NO_ICACHE |
// No instruction cache |
altor32_noicache |
u_icache |
200,12 → 206,13
.valid_o(icache_valid), |
|
// Instruction memory |
.mem_addr_o(imem_addr_o), |
.mem_data_i(imem_data_in_i), |
.mem_burst_o(imem_burst_o), |
.mem_rd_o(imem_rd_o), |
.mem_accept_i(imem_accept_i), |
.mem_ack_i(imem_ack_i) |
.wbm_addr_o(imem_addr_o), |
.wbm_dat_i(imem_dat_i), |
.wbm_cti_o(imem_cti_o), |
.wbm_cyc_o(imem_cyc_o), |
.wbm_stb_o(imem_stb_o), |
.wbm_stall_i(imem_stall_i), |
.wbm_ack_i(imem_ack_i) |
); |
end |
endgenerate |
246,7 → 253,7
// Register file |
generate |
if (REGISTER_FILE_TYPE == "XILINX") |
begin |
begin : REGFILE_XIL |
altor32_regfile_xil |
#( |
.SUPPORT_32REGS(SUPPORT_32REGS) |
268,7 → 275,7
); |
end |
else if (REGISTER_FILE_TYPE == "ALTERA") |
begin |
begin : REGFILE_ALT |
altor32_regfile_alt |
#( |
.SUPPORT_32REGS(SUPPORT_32REGS) |
290,7 → 297,7
); |
end |
else |
begin |
begin : REGFILE_SIM |
altor32_regfile_sim |
#( |
.SUPPORT_32REGS(SUPPORT_32REGS) |
315,7 → 322,7
|
generate |
if (ENABLE_DCACHE == "ENABLED") |
begin |
begin : DCACHE |
// Data cache |
altor32_dcache |
u_dcache |
329,34 → 336,39
.address_i({dcache_addr[31:2], 2'b00}), |
.data_o(dcache_data_i), |
.data_i(dcache_data_o), |
.wr_i(dcache_wr), |
.rd_i(dcache_rd), |
.accept_o(dcache_accept), |
.we_i(dcache_we), |
.stb_i(dcache_stb), |
.sel_i(dcache_sel), |
.stall_o(dcache_stall), |
.ack_o(dcache_ack), |
|
// Memory interface (slave) |
.mem_addr_o(dmem_addr_o), |
.mem_data_i(dmem_data_in_i), |
.mem_data_o(dmem_data_out_o), |
.mem_burst_o(dmem_burst_o), |
.mem_rd_o(dmem_rd_o), |
.mem_wr_o(dmem_wr_o), |
.mem_accept_i(dmem_accept_i), |
.mem_data_i(dmem_dat_i), |
.mem_data_o(dmem_dat_o), |
.mem_sel_o(dmem_sel_o), |
.mem_we_o(dmem_we_o), |
.mem_stb_o(dmem_stb_o), |
.mem_cyc_o(dmem_cyc_o), |
.mem_cti_o(dmem_cti_o), |
.mem_stall_i(dmem_stall_i), |
.mem_ack_i(dmem_ack_i) |
); |
end |
else |
begin |
begin: NO_DCACHE |
|
// No data cache |
assign dmem_addr_o = {dcache_addr[31:2], 2'b00}; |
assign dmem_data_out_o = dcache_data_o; |
assign dcache_data_i = dmem_data_in_i; |
assign dmem_rd_o = dcache_rd; |
assign dmem_wr_o = dcache_wr; |
assign dmem_burst_o = 1'b0; |
assign dmem_dat_o = dcache_data_o; |
assign dcache_data_i = dmem_dat_i; |
assign dmem_sel_o = dcache_sel; |
assign dmem_cyc_o = dcache_cyc; |
assign dmem_we_o = dcache_we; |
assign dmem_stb_o = dcache_stb; |
assign dmem_cti_o = 3'b111; |
assign dcache_ack = dmem_ack_i; |
assign dcache_accept = dmem_accept_i; |
assign dcache_stall = dmem_stall_i; |
end |
endgenerate |
|
416,9 → 428,11
.dmem_addr_o(dcache_addr), |
.dmem_data_out_o(dcache_data_o), |
.dmem_data_in_i(dcache_data_i), |
.dmem_wr_o(dcache_wr), |
.dmem_rd_o(dcache_rd), |
.dmem_accept_i(dcache_accept), |
.dmem_sel_o(dcache_sel), |
.dmem_we_o(dcache_we), |
.dmem_stb_o(dcache_stb), |
.dmem_cyc_o(dcache_cyc), |
.dmem_stall_i(dcache_stall), |
.dmem_ack_i(dcache_ack) |
); |
|
/rtl/cpu/altor32_dcache_mem_if.v
62,13 → 62,15
|
// Memory interface (slave) |
output reg [31:0] mem_addr_o /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
input [31:0] mem_data_i /*verilator public*/, |
output reg [31:0] mem_data_o /*verilator public*/, |
output reg mem_burst_o /*verilator public*/, |
output reg mem_rd_o /*verilator public*/, |
output reg [3:0] mem_wr_o /*verilator public*/, |
input mem_accept_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
output reg [2:0] mem_cti_o /*verilator public*/, |
output reg mem_cyc_o /*verilator public*/, |
output reg mem_stb_o /*verilator public*/, |
output reg mem_we_o /*verilator public*/, |
output reg [3:0] mem_sel_o /*verilator public*/, |
input mem_stall_i/*verilator public*/, |
input mem_ack_i/*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
82,53 → 84,195
//----------------------------------------------------------------- |
|
reg [31:CACHE_LINE_SIZE_WIDTH] line_address; |
reg [CACHE_LINE_SIZE_WIDTH-3:0] line_word; |
|
reg [CACHE_LINE_WORDS_IDX_MAX-1:0] response_idx; |
|
reg [CACHE_LINE_WORDS_IDX_MAX-1:0] request_idx; |
wire [CACHE_LINE_WORDS_IDX_MAX-1:0] next_request_idx = request_idx + 1'b1; |
|
reg [CACHE_LINE_WORDS_IDX_MAX-1:0] cache_idx; |
wire [CACHE_LINE_WORDS_IDX_MAX-1:0] next_cache_idx = cache_idx + 1'b1; |
|
|
// Current state |
parameter STATE_IDLE = 0; |
parameter STATE_FETCH = 1; |
parameter STATE_READ_WAIT = 2; |
parameter STATE_WRITE_SETUP = 2; |
parameter STATE_WRITE = 3; |
parameter STATE_WRITE_WAIT = 4; |
parameter STATE_READ_SINGLE = 5; |
parameter STATE_WRITE_SINGLE= 6; |
parameter STATE_MEM_SINGLE = 5; |
parameter STATE_FETCH_WAIT = 6; |
|
reg [3:0] state; |
|
//----------------------------------------------------------------- |
// Control logic |
// Next State Logic |
//----------------------------------------------------------------- |
reg [CACHE_LINE_SIZE_WIDTH-3:0] v_line_word; |
reg [3:0] next_state_r; |
always @ * |
begin |
next_state_r = state; |
|
case (state) |
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Perform cache evict (write) |
if (evict_i) |
next_state_r = STATE_WRITE_SETUP; |
// Perform cache fill (read) |
else if (fill_i) |
next_state_r = STATE_FETCH; |
// Read/Write single |
else if (rd_single_i | (|wr_single_i)) |
next_state_r = STATE_MEM_SINGLE; |
end |
//----------------------------------------- |
// FETCH - Fetch line from memory |
//----------------------------------------- |
STATE_FETCH : |
begin |
// Line fetch complete? |
if (~mem_stall_i && request_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
next_state_r = STATE_FETCH_WAIT; |
end |
//----------------------------------------- |
// FETCH_WAIT - Wait for read responses |
//----------------------------------------- |
STATE_FETCH_WAIT: |
begin |
// Read from memory complete |
if (mem_ack_i && response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// WRITE_SETUP - Wait for data from cache |
//----------------------------------------- |
STATE_WRITE_SETUP : |
next_state_r = STATE_WRITE; |
//----------------------------------------- |
// WRITE - Write word to memory |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Line write complete? |
if (~mem_stall_i && request_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
next_state_r = STATE_WRITE_WAIT; |
// Fetch next word for line |
else if (~mem_stall_i | ~mem_stb_o) |
next_state_r = STATE_WRITE_SETUP; |
end |
//----------------------------------------- |
// WRITE_WAIT - Wait for write to complete |
//----------------------------------------- |
STATE_WRITE_WAIT: |
begin |
// Write to memory complete |
if (mem_ack_i && response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
next_state_r = STATE_IDLE; |
end |
//----------------------------------------- |
// MEM_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_MEM_SINGLE: |
begin |
// Data ready from memory? |
if (mem_ack_i) |
next_state_r = STATE_IDLE; |
end |
default: |
; |
endcase |
end |
|
// Update state |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
state <= STATE_IDLE; |
else |
state <= next_state_r; |
end |
|
//----------------------------------------------------------------- |
// Control logic |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
line_address <= {32-CACHE_LINE_SIZE_WIDTH{1'b0}}; |
line_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
mem_addr_o <= 32'h00000000; |
mem_data_o <= 32'h00000000; |
mem_wr_o <= 4'h0; |
mem_rd_o <= 1'b0; |
mem_burst_o <= 1'b0; |
cache_addr_o <= 30'h00000000; |
cache_data_o <= 32'h00000000; |
cache_wr_o <= 1'b0; |
done_o <= 1'b0; |
data_o <= 32'h00000000; |
state <= STATE_IDLE; |
end |
else |
begin |
|
if (mem_accept_i) |
begin |
mem_rd_o <= 1'b0; |
mem_wr_o <= 4'h0; |
end |
done_o <= 1'b0; |
|
case (state) |
|
done_o <= 1'b0; |
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Perform cache evict (write) |
if (evict_i) |
line_address <= evict_addr_i[31:CACHE_LINE_SIZE_WIDTH]; |
// Perform cache fill (read) |
else if (fill_i) |
line_address <= address_i[31:CACHE_LINE_SIZE_WIDTH]; |
end |
//----------------------------------------- |
// FETCH/WRITE_WAIT - Wait for oustanding responses |
//----------------------------------------- |
STATE_WRITE_WAIT, |
STATE_FETCH_WAIT: |
begin |
// Write to memory complete |
if (mem_ack_i) |
begin |
// Line write complete? |
if (response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
done_o <= 1'b1; |
end |
end |
//----------------------------------------- |
// MEM_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_MEM_SINGLE: |
begin |
// Data ready from memory? |
if (mem_ack_i) |
begin |
data_o <= mem_data_i; |
done_o <= 1'b1; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Cache Read / Write |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
cache_addr_o <= 30'h00000000; |
cache_data_o <= 32'h00000000; |
cache_wr_o <= 1'b0; |
|
cache_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
end |
else |
begin |
cache_wr_o <= 1'b0; |
|
case (state) |
|
137,27 → 281,114
//----------------------------------------- |
STATE_IDLE : |
begin |
cache_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
|
// Perform cache evict (write) |
if (evict_i) |
begin |
line_address <= evict_addr_i[31:CACHE_LINE_SIZE_WIDTH]; |
line_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
|
// Read data from cache |
cache_addr_o <= {evict_addr_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH-2{1'b0}}}; |
state <= STATE_READ_WAIT; |
cache_addr_o <= {evict_addr_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_WORDS_IDX_MAX{1'b0}}}; |
end |
end |
//----------------------------------------- |
// FETCH - Fetch line from memory |
//----------------------------------------- |
STATE_FETCH, |
STATE_FETCH_WAIT: |
begin |
// Data ready from memory? |
if (mem_ack_i) |
begin |
// Write data into cache |
cache_addr_o <= {line_address, cache_idx}; |
cache_data_o <= mem_data_i; |
cache_wr_o <= 1'b1; |
|
cache_idx <= next_cache_idx; |
end |
end |
//----------------------------------------- |
// WRITE - Write word to memory |
//----------------------------------------- |
STATE_WRITE_SETUP: |
begin |
|
end |
STATE_WRITE, |
STATE_WRITE_WAIT: |
begin |
if (~mem_stall_i | ~mem_stb_o) |
begin |
// Setup next word read from cache |
cache_addr_o <= {line_address, next_cache_idx}; |
cache_idx <= next_cache_idx; |
end |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// Request |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
begin |
mem_addr_o <= 32'h00000000; |
mem_data_o <= 32'h00000000; |
mem_sel_o <= 4'h0; |
mem_cti_o <= 3'b0; |
mem_stb_o <= 1'b0; |
mem_we_o <= 1'b0; |
request_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
end |
else |
begin |
if (~mem_stall_i) |
begin |
mem_stb_o <= 1'b0; |
|
// TMP |
if (mem_cti_o == 3'b111) |
begin |
//mem_addr_o <= 32'h00000000; |
mem_data_o <= 32'h00000000; |
mem_sel_o <= 4'h0; |
mem_cti_o <= 3'b0; |
mem_stb_o <= 1'b0; |
mem_we_o <= 1'b0; |
end |
end |
|
case (state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
request_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
|
// Perform cache evict (write) |
if (evict_i) |
begin |
|
end |
// Perform cache fill (read) |
else if (fill_i) |
begin |
line_address <= address_i[31:CACHE_LINE_SIZE_WIDTH]; |
line_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}}; |
|
// Start fetch from memory |
mem_addr_o <= {address_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}}; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b1; |
state <= STATE_FETCH; |
mem_data_o <= 32'h00000000; |
mem_sel_o <= 4'b1111; |
mem_cti_o <= 3'b010; |
mem_stb_o <= 1'b1; |
mem_we_o <= 1'b0; |
|
request_idx <= next_request_idx; |
end |
// Read single |
else if (rd_single_i) |
164,10 → 395,11
begin |
// Start fetch from memory |
mem_addr_o <= address_i; |
mem_data_o <= 32'b0; |
mem_rd_o <= 1'b1; |
mem_burst_o <= 1'b0; |
state <= STATE_READ_SINGLE; |
mem_data_o <= 32'h00000000; |
mem_sel_o <= 4'b1111; |
mem_cti_o <= 3'b111; |
mem_stb_o <= 1'b1; |
mem_we_o <= 1'b0; |
end |
// Write single |
else if (|wr_single_i) |
175,9 → 407,10
// Start fetch from memory |
mem_addr_o <= address_i; |
mem_data_o <= data_i; |
mem_wr_o <= wr_single_i; |
mem_burst_o <= 1'b0; |
state <= STATE_WRITE_SINGLE; |
mem_sel_o <= wr_single_i; |
mem_cti_o <= 3'b111; |
mem_stb_o <= 1'b1; |
mem_we_o <= 1'b1; |
end |
end |
//----------------------------------------- |
185,110 → 418,160
//----------------------------------------- |
STATE_FETCH : |
begin |
// Data ready from memory? |
if (mem_ack_i && mem_rd_o == 1'b0) |
// Previous request accepted? |
if (~mem_stall_i) |
begin |
// Write data into cache |
cache_addr_o <= {line_address, line_word}; |
cache_data_o <= mem_data_i; |
cache_wr_o <= 1'b1; |
|
// Line fetch complete? |
if (line_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
begin |
done_o <= 1'b1; |
state <= STATE_IDLE; |
end |
// Fetch next word for line |
else |
begin |
v_line_word = line_word + 1'b1; |
line_word <= v_line_word; |
|
mem_addr_o <= {line_address, v_line_word, 2'b00}; |
mem_rd_o <= 1'b1; |
|
if (line_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1)) |
begin |
mem_burst_o <= 1'b0; |
end |
end |
mem_addr_o <= {line_address, request_idx, 2'b00}; |
mem_stb_o <= 1'b1; |
|
if (request_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
mem_cti_o <= 3'b111; |
|
request_idx <= next_request_idx; |
end |
end |
//----------------------------------------- |
// READ_WAIT - Wait for data from cache |
//----------------------------------------- |
STATE_READ_WAIT : |
begin |
// Not used yet, but set for start of burst |
mem_burst_o <= 1'b1; |
state <= STATE_WRITE; |
end |
//----------------------------------------- |
// WRITE - Write word to memory |
//----------------------------------------- |
STATE_WRITE : |
begin |
// Write data into memory from cache |
mem_addr_o <= {line_address, line_word, 2'b00}; |
mem_data_o <= cache_data_i; |
mem_wr_o <= 4'b1111; |
// Memory interface can request command? |
if (~mem_stall_i | ~mem_stb_o) |
begin |
// Write data into memory from cache |
mem_addr_o <= {line_address, request_idx, 2'b00}; |
mem_data_o <= cache_data_i; |
mem_sel_o <= 4'b1111; |
mem_stb_o <= 1'b1; |
mem_we_o <= 1'b1; |
|
if (request_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
mem_cti_o <= 3'b111; |
else |
mem_cti_o <= 3'b010; |
|
// Setup next word read from cache |
v_line_word = line_word + 1'b1; |
cache_addr_o <= {line_address, v_line_word}; |
request_idx <= next_request_idx; |
end |
end |
default: |
; |
endcase |
end |
end |
|
state <= STATE_WRITE_WAIT; |
end |
//----------------------------------------------------------------- |
// Memory Response Counter |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
response_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
else |
begin |
case (state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
response_idx <= {CACHE_LINE_WORDS_IDX_MAX{1'b0}}; |
end |
//----------------------------------------- |
// FETCH - Fetch line from memory |
//----------------------------------------- |
STATE_FETCH, |
STATE_FETCH_WAIT : |
begin |
// Data ready from memory? |
if (mem_ack_i) |
response_idx <= response_idx + 1'b1; |
end |
//----------------------------------------- |
// WRITE_WAIT - Wait for write to complete |
//----------------------------------------- |
STATE_WRITE, |
STATE_WRITE_SETUP, |
STATE_WRITE_WAIT: |
begin |
// Write to memory complete |
if (mem_ack_i && mem_wr_o == 4'b0) |
if (mem_ack_i) |
response_idx <= response_idx + 1'b1; |
end |
default: |
; |
endcase |
end |
end |
|
//----------------------------------------------------------------- |
// CYC_O |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
begin |
if (rst_i == 1'b1) |
mem_cyc_o <= 1'b0; |
else |
begin |
case (state) |
|
//----------------------------------------- |
// IDLE |
//----------------------------------------- |
STATE_IDLE : |
begin |
// Perform cache evict (write) |
if (evict_i) |
begin |
// Line write complete? |
if (line_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
begin |
done_o <= 1'b1; |
state <= STATE_IDLE; |
end |
// Fetch next word for line |
else |
begin |
line_word <= line_word + 1'b1; |
state <= STATE_WRITE; |
|
if (line_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1)) |
mem_burst_o <= 1'b0; |
end |
|
end |
end |
// Perform cache fill (read) |
else if (fill_i) |
mem_cyc_o <= 1'b1; |
// Read single |
else if (rd_single_i) |
mem_cyc_o <= 1'b1; |
// Write single |
else if (|wr_single_i) |
mem_cyc_o <= 1'b1; |
end |
//----------------------------------------- |
// READ_SINGLE - Single access to memory |
// FETCH - Fetch line from memory |
//----------------------------------------- |
STATE_READ_SINGLE: |
STATE_FETCH : |
begin |
// Data ready from memory? |
if (mem_ack_i && mem_rd_o == 1'b0) |
begin |
data_o <= mem_data_i; |
done_o <= 1'b1; |
state <= STATE_IDLE; |
end |
if (mem_ack_i && response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
mem_cyc_o <= 1'b0; |
end |
//----------------------------------------- |
// WRITE_SINGLE - Single access to memory |
// WRITE - Write word to memory |
//----------------------------------------- |
STATE_WRITE_SINGLE: |
STATE_WRITE : |
begin |
if (mem_ack_i && mem_wr_o == 4'b0) |
begin |
done_o <= 1'b1; |
state <= STATE_IDLE; |
end |
end |
// Write data into memory from cache |
mem_cyc_o <= 1'b1; |
end |
//----------------------------------------- |
// FETCH/WRITE_WAIT - Wait for responses |
//----------------------------------------- |
STATE_WRITE_WAIT, |
STATE_FETCH_WAIT: |
begin |
// Write to memory complete |
if (mem_ack_i && response_idx == {CACHE_LINE_WORDS_IDX_MAX{1'b1}}) |
mem_cyc_o <= 1'b0; |
end |
//----------------------------------------- |
// MEM_SINGLE - Single access to memory |
//----------------------------------------- |
STATE_MEM_SINGLE: |
begin |
// Data ready from memory? |
if (mem_ack_i) |
mem_cyc_o <= 1'b0; |
end |
default: |
; |
endcase |
/rtl/cpu/altor32_exec.v
36,9 → 36,7
//----------------------------------------------------------------- |
|
//`define CONF_CORE_DEBUG |
//`define CONF_CORE_DEBUG_BUBBLE |
//`define CONF_CORE_TRACE |
//`define CONF_CORE_FAULT_ON_OPCODE0 |
|
//----------------------------------------------------------------- |
// Includes |
106,9 → 104,11
output reg [31:0] dmem_addr_o /*verilator public*/, |
output reg [31:0] dmem_data_out_o /*verilator public*/, |
input [31:0] dmem_data_in_i /*verilator public*/, |
output reg [3:0] dmem_wr_o /*verilator public*/, |
output reg dmem_rd_o /*verilator public*/, |
input dmem_accept_i /*verilator public*/, |
output reg [3:0] dmem_sel_o /*verilator public*/, |
output reg dmem_we_o /*verilator public*/, |
output reg dmem_stb_o /*verilator public*/, |
output reg dmem_cyc_o /*verilator public*/, |
input dmem_stall_i /*verilator public*/, |
input dmem_ack_i /*verilator public*/ |
); |
|
749,170 → 749,106
//----------------------------------------------------------------- |
// Comparisons |
//----------------------------------------------------------------- |
reg [31:0] compare_a_r; |
reg [31:0] compare_b_r; |
always @ * |
begin |
compare_a_r = reg_ra_r; |
compare_b_r = reg_rb_r; |
|
case (1'b1) |
inst_sfeqi_w, // l.sfeqi |
inst_sfgesi_w, // l.sfgesi |
inst_sfgeui_w, // l.sfgeui |
inst_sfgtsi_w, // l.sfgtsi |
inst_sfgtui_w, // l.sfgtui |
inst_sflesi_w, // l.sflesi |
inst_sfleui_w, // l.sfleui |
inst_sfltsi_w, // l.sfltsi |
inst_sfltui_w, // l.sfltui |
inst_sfnei_w: // l.sfnei |
compare_b_r = int32_r; |
default: |
; |
endcase |
end |
|
reg compare_equal_r; |
reg compare_gts_r; |
reg compare_gt_r; |
reg compare_lts_r; |
reg compare_lt_r; |
always @ * |
begin |
if (compare_a_r == compare_b_r) |
compare_equal_r = 1'b1; |
else |
compare_equal_r = 1'b0; |
|
compare_lts_r = less_than_signed(compare_a_r, compare_b_r); |
|
if (compare_a_r < compare_b_r) |
compare_lt_r = 1'b1; |
else |
compare_lt_r = 1'b0; |
|
// Greater than (signed) |
compare_gts_r = ~(compare_lts_r | compare_equal_r); |
|
if (compare_a_r > compare_b_r) |
compare_gt_r = 1'b1; |
else |
compare_gt_r = 1'b0; |
end |
|
always @ * |
begin |
compare_result_r = 1'b0; |
|
case (1'b1) |
inst_sfeq_w: // l.sfeq |
begin |
if (reg_ra_r == reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfeq_w, // l.sfeq |
inst_sfeqi_w: // l.sfeqi |
begin |
if (reg_ra_r == int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_equal_r; |
|
inst_sfges_w: // l.sfges |
begin |
if (greater_than_equal_signed(reg_ra_r, reg_rb_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfges_w, // l.sfges |
inst_sfgesi_w: // l.sfgesi |
begin |
if (greater_than_equal_signed(reg_ra_r, int32_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_gts_r | compare_equal_r; |
|
inst_sfgeu_w: // l.sfgeu |
begin |
if (reg_ra_r >= reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfgeu_w, // l.sfgeu |
inst_sfgeui_w: // l.sfgeui |
begin |
if (reg_ra_r >= int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_gt_r | compare_equal_r; |
|
inst_sfgts_w: // l.sfgts |
begin |
if (greater_than_signed(reg_ra_r, reg_rb_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfgts_w, // l.sfgts |
inst_sfgtsi_w: // l.sfgtsi |
begin |
if (greater_than_signed(reg_ra_r, int32_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_gts_r; |
|
inst_sfgtu_w: // l.sfgtu |
begin |
if (reg_ra_r > reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfgtu_w, // l.sfgtu |
inst_sfgtui_w: // l.sfgtui |
begin |
if (reg_ra_r > int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_gt_r; |
|
inst_sfles_w: // l.sfles |
begin |
if (less_than_equal_signed(reg_ra_r, reg_rb_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
|
inst_sfles_w, // l.sfles |
inst_sflesi_w: // l.sflesi |
begin |
if (less_than_equal_signed(reg_ra_r, int32_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_lts_r | compare_equal_r; |
|
inst_sfleu_w: // l.sfleu |
begin |
if (reg_ra_r <= reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
inst_sfleu_w, // l.sfleu |
|
inst_sfleui_w: // l.sfleui |
begin |
if (reg_ra_r <= int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_lt_r | compare_equal_r; |
|
inst_sflts_w: // l.sflts |
begin |
if (less_than_signed(reg_ra_r, reg_rb_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
inst_sflts_w, // l.sflts |
|
inst_sfltsi_w: // l.sfltsi |
begin |
if (less_than_signed(reg_ra_r, int32_r) == 1'b1) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_lts_r; |
|
inst_sfltu_w: // l.sfltu |
begin |
if (reg_ra_r < reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
inst_sfltu_w, // l.sfltu |
|
inst_sfltui_w: // l.sfltui |
begin |
if (reg_ra_r < int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = compare_lt_r; |
|
inst_sfne_w: // l.sfne |
begin |
if (reg_ra_r != reg_rb_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
inst_sfne_w, // l.sfne |
|
inst_sfnei_w: // l.sfnei |
begin |
if (reg_ra_r != int32_r) |
compare_result_r = 1'b1; |
else |
compare_result_r = 1'b0; |
end |
compare_result_r = ~compare_equal_r; |
default: |
; |
endcase |
1330,8 → 1266,10
// Data memory |
dmem_addr_o <= 32'h00000000; |
dmem_data_out_o <= 32'h00000000; |
dmem_rd_o <= 1'b0; |
dmem_wr_o <= 4'b0000; |
dmem_we_o <= 1'b0; |
dmem_sel_o <= 4'b0000; |
dmem_stb_o <= 1'b0; |
dmem_cyc_o <= 1'b0; |
|
r_mem_load <= 1'b0; |
r_mem_store <= 1'b0; |
1347,12 → 1285,11
begin |
|
// If memory access accepted by slave |
if (dmem_accept_i) |
begin |
dmem_rd_o <= 1'b0; |
dmem_wr_o <= 4'b0000; |
end |
|
if (~dmem_stall_i) |
dmem_stb_o <= 1'b0; |
|
if (dmem_ack_i) |
dmem_cyc_o <= 1'b0; |
r_mem_access <= 1'b0; |
d_mem_load <= r_mem_access & r_mem_load; |
|
1391,7 → 1328,10
begin |
dmem_addr_o <= mem_addr_r; |
dmem_data_out_o <= 32'h00000000; |
dmem_rd_o <= 1'b1; |
dmem_sel_o <= 4'b1111; |
dmem_we_o <= 1'b0; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
|
// Mark load as pending |
r_mem_load <= 1'b1; |
1415,32 → 1355,41
2'b00 : |
begin |
dmem_data_out_o <= {reg_rb_r[7:0],24'h000000}; |
dmem_wr_o <= 4'b1000; |
dmem_sel_o <= 4'b1000; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
2'b01 : |
begin |
dmem_data_out_o <= {{8'h00,reg_rb_r[7:0]},16'h0000}; |
dmem_wr_o <= 4'b0100; |
dmem_sel_o <= 4'b0100; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
2'b10 : |
begin |
dmem_data_out_o <= {{16'h0000,reg_rb_r[7:0]},8'h00}; |
dmem_wr_o <= 4'b0010; |
dmem_sel_o <= 4'b0010; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
2'b11 : |
begin |
dmem_data_out_o <= {24'h000000,reg_rb_r[7:0]}; |
dmem_wr_o <= 4'b0001; |
dmem_sel_o <= 4'b0001; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
default : |
begin |
dmem_data_out_o <= 32'h00000000; |
dmem_wr_o <= 4'b0000; |
end |
; |
endcase |
end |
|
1452,20 → 1401,23
2'b00 : |
begin |
dmem_data_out_o <= {reg_rb_r[15:0],16'h0000}; |
dmem_wr_o <= 4'b1100; |
dmem_sel_o <= 4'b1100; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
2'b10 : |
begin |
dmem_data_out_o <= {16'h0000,reg_rb_r[15:0]}; |
dmem_wr_o <= 4'b0011; |
dmem_sel_o <= 4'b0011; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_store <= 1'b1; |
end |
default : |
begin |
dmem_data_out_o <= 32'h00000000; |
dmem_wr_o <= 4'b0000; |
end |
; |
endcase |
end |
|
1473,7 → 1425,10
begin |
dmem_addr_o <= mem_addr_r; |
dmem_data_out_o <= reg_rb_r; |
dmem_wr_o <= 4'b1111; |
dmem_sel_o <= 4'b1111; |
dmem_we_o <= 1'b1; |
dmem_stb_o <= 1'b1; |
dmem_cyc_o <= 1'b1; |
r_mem_access <= 1'b1; |
r_mem_store <= 1'b1; |
|
1619,6 → 1574,26
get_putc = 8'b0; |
`endif |
endfunction |
function [0:0] get_reg_valid; |
// verilator public |
get_reg_valid = ~(resolve_failed | load_stall); |
endfunction |
function [4:0] get_reg_ra; |
// verilator public |
get_reg_ra = reg_ra_i; |
endfunction |
function [31:0] get_reg_ra_value; |
// verilator public |
get_reg_ra_value = ra_value_resolved; |
endfunction |
function [4:0] get_reg_rb; |
// verilator public |
get_reg_rb = reg_rb_i; |
endfunction |
function [31:0] get_reg_rb_value; |
// verilator public |
get_reg_rb_value = rb_value_resolved; |
endfunction |
`endif |
|
endmodule |
/rtl/cpu/altor32_regfile_sim.v
45,15 → 45,15
//----------------------------------------------------------------- |
module altor32_regfile_sim |
( |
input clk_i /*verilator public*/, |
input rst_i /*verilator public*/, |
input wr_i /*verilator public*/, |
input [4:0] rs_i /*verilator public*/, |
input [4:0] rt_i /*verilator public*/, |
input [4:0] rd_i /*verilator public*/, |
output [31:0] reg_rs_o /*verilator public*/, |
output [31:0] reg_rt_o /*verilator public*/, |
input [31:0] reg_rd_i /*verilator public*/ |
input clk_i /*verilator public*/, |
input rst_i /*verilator public*/, |
input wr_i /*verilator public*/, |
input [4:0] rs_i /*verilator public*/, |
input [4:0] rt_i /*verilator public*/, |
input [4:0] rd_i /*verilator public*/, |
output reg [31:0] reg_rs_o /*verilator public*/, |
output reg [31:0] reg_rt_o /*verilator public*/, |
input [31:0] reg_rd_i /*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
98,9 → 98,6
reg [31:0] reg_r30; |
reg [31:0] reg_r31; |
|
reg [31:0] reg_rs_o; |
reg [31:0] reg_rt_o; |
|
//----------------------------------------------------------------- |
// Register File (for simulation) |
//----------------------------------------------------------------- |
/rtl/sim/ram.v
1,4 → 1,41
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: ram - dual port block RAM |
//----------------------------------------------------------------- |
module ram |
5,19 → 42,25
( |
// Port A |
input clka_i /*verilator public*/, |
input ena_i /*verilator public*/, |
input [3:0] wea_i /*verilator public*/, |
input rsta_i /*verilator public*/, |
input stba_i /*verilator public*/, |
input wea_i /*verilator public*/, |
input [3:0] sela_i /*verilator public*/, |
input [31:2] addra_i /*verilator public*/, |
input [31:0] dataa_i /*verilator public*/, |
output [31:0] dataa_o /*verilator public*/, |
output reg acka_o /*verilator public*/, |
|
// Port B |
input clkb_i /*verilator public*/, |
input enb_i /*verilator public*/, |
input [3:0] web_i /*verilator public*/, |
input rstb_i /*verilator public*/, |
input stbb_i /*verilator public*/, |
input web_i /*verilator public*/, |
input [3:0] selb_i /*verilator public*/, |
input [31:2] addrb_i /*verilator public*/, |
input [31:0] datab_i /*verilator public*/, |
output [31:0] datab_o /*verilator public*/ |
output [31:0] datab_o /*verilator public*/, |
output reg ackb_o /*verilator public*/ |
); |
|
//----------------------------------------------------------------- |
30,6 → 73,9
// Instantiation |
//----------------------------------------------------------------- |
|
wire [3:0] wr_a = {4{stba_i}} & {4{wea_i}} & sela_i; |
wire [3:0] wr_b = {4{stbb_i}} & {4{web_i}} & selb_i; |
|
ram_dp8 |
#( |
.WIDTH(8), |
41,13 → 87,13
.aadr_i(addra_i[SIZE+2-1:2]), |
.adat_o(dataa_o[7:0]), |
.adat_i(dataa_i[7:0]), |
.awr_i(wea_i[0]), |
.awr_i(wr_a[0]), |
|
.bclk_i(clkb_i), |
.badr_i(addrb_i[SIZE+2-1:2]), |
.bdat_o(datab_o[7:0]), |
.bdat_i(datab_i[7:0]), |
.bwr_i(web_i[0]) |
.bwr_i(wr_b[0]) |
); |
|
ram_dp8 |
61,13 → 107,13
.aadr_i(addra_i[SIZE+2-1:2]), |
.adat_o(dataa_o[15:8]), |
.adat_i(dataa_i[15:8]), |
.awr_i(wea_i[1]), |
.awr_i(wr_a[1]), |
|
.bclk_i(clkb_i), |
.badr_i(addrb_i[SIZE+2-1:2]), |
.bdat_o(datab_o[15:8]), |
.bdat_i(datab_i[15:8]), |
.bwr_i(web_i[1]) |
.bwr_i(wr_b[1]) |
); |
|
ram_dp8 |
81,13 → 127,13
.aadr_i(addra_i[SIZE+2-1:2]), |
.adat_o(dataa_o[23:16]), |
.adat_i(dataa_i[23:16]), |
.awr_i(wea_i[2]), |
.awr_i(wr_a[2]), |
|
.bclk_i(clkb_i), |
.badr_i(addrb_i[SIZE+2-1:2]), |
.bdat_o(datab_o[23:16]), |
.bdat_i(datab_i[23:16]), |
.bwr_i(web_i[2]) |
.bwr_i(wr_b[2]) |
); |
|
ram_dp8 |
101,13 → 147,39
.aadr_i(addra_i[SIZE+2-1:2]), |
.adat_o(dataa_o[31:24]), |
.adat_i(dataa_i[31:24]), |
.awr_i(wea_i[3]), |
.awr_i(wr_a[3]), |
|
.bclk_i(clkb_i), |
.badr_i(addrb_i[SIZE+2-1:2]), |
.bdat_o(datab_o[31:24]), |
.bdat_i(datab_i[31:24]), |
.bwr_i(web_i[3]) |
.bwr_i(wr_b[3]) |
); |
|
// AckA |
always @(posedge clka_i or posedge rsta_i) |
begin |
if (rsta_i == 1'b1) |
begin |
acka_o <= 1'b0; |
end |
else |
begin |
acka_o <= stba_i; |
end |
end |
|
// AckB |
always @(posedge clkb_i or posedge rstb_i) |
begin |
if (rstb_i == 1'b1) |
begin |
ackb_o <= 1'b0; |
end |
else |
begin |
ackb_o <= stbb_i; |
end |
end |
|
endmodule |
/rtl/sim/top.v
64,26 → 64,32
wire [31:0] soc_addr; |
wire [31:0] soc_data_w; |
wire [31:0] soc_data_r; |
wire [3:0] soc_wr; |
wire soc_rd; |
wire soc_we; |
wire soc_stb; |
wire soc_ack; |
wire soc_irq; |
|
wire[31:0] dmem_address; |
wire[31:0] dmem_data_w; |
wire[31:0] dmem_data_r; |
wire[3:0] dmem_wr; |
wire dmem_rd; |
wire dmem_burst; |
wire[3:0] dmem_sel; |
wire[2:0] dmem_cti; |
wire dmem_we; |
wire dmem_stb; |
wire dmem_cyc; |
wire dmem_stall; |
wire dmem_ack; |
reg dmem_req_r; |
|
wire[31:0] imem_addr; |
wire[31:0] imem_data; |
wire imem_rd; |
wire imem_burst; |
wire[3:0] imem_sel; |
wire imem_stb; |
wire imem_cyc; |
wire[2:0] imem_cti; |
wire imem_stall; |
wire imem_ack; |
reg imem_req_r; |
|
|
//----------------------------------------------------------------- |
// Instantiation |
//----------------------------------------------------------------- |
96,21 → 102,26
u_ram |
( |
.clka_i(clk_i), |
.ena_i(1'b1), |
.wea_i(4'b0), |
.rsta_i(rst_i), |
.stba_i(imem_stb), |
.wea_i(1'b0), |
.sela_i(imem_sel), |
.addra_i(imem_addr[31:2]), |
.dataa_i(32'b0), |
.dataa_o(imem_data), |
.acka_o(imem_ack), |
|
.clkb_i(clk_i), |
.enb_i(1'b1), |
.web_i(dmem_wr), |
.rstb_i(rst_i), |
.stbb_i(dmem_stb), |
.web_i(dmem_we), |
.selb_i(dmem_sel), |
.addrb_i(dmem_address[31:2]), |
.datab_i(dmem_data_w), |
.datab_o(dmem_data_r) |
.datab_o(dmem_data_r), |
.ackb_o(dmem_ack) |
); |
|
|
// CPU |
cpu_if |
#( |
133,10 → 144,12
|
// Instruction Memory 0 (0x10000000 - 0x10FFFFFF) |
.imem0_addr_o(imem_addr), |
.imem0_rd_o(imem_rd), |
.imem0_burst_o(imem_burst), |
.imem0_data_in_i(imem_data), |
.imem0_accept_i(1'b1), |
.imem0_data_i(imem_data), |
.imem0_sel_o(imem_sel), |
.imem0_cti_o(imem_cti), |
.imem0_cyc_o(imem_cyc), |
.imem0_stb_o(imem_stb), |
.imem0_stall_i(1'b0), |
.imem0_ack_i(imem_ack), |
|
// Data Memory 0 (0x10000000 - 0x10FFFFFF) |
143,20 → 156,24
.dmem0_addr_o(dmem_address), |
.dmem0_data_o(dmem_data_w), |
.dmem0_data_i(dmem_data_r), |
.dmem0_wr_o(dmem_wr), |
.dmem0_rd_o(dmem_rd), |
.dmem0_accept_i(1'b1), |
.dmem0_burst_o(dmem_burst), |
.dmem0_sel_o(dmem_sel), |
.dmem0_cti_o(dmem_cti), |
.dmem0_cyc_o(dmem_cyc), |
.dmem0_we_o(dmem_we), |
.dmem0_stb_o(dmem_stb), |
.dmem0_stall_i(1'b0), |
.dmem0_ack_i(dmem_ack), |
|
// Data Memory 1 (0x11000000 - 0x11FFFFFF) |
.dmem1_addr_o(), |
.dmem1_data_o(), |
.dmem1_addr_o(/*open*/), |
.dmem1_data_o(/*open*/), |
.dmem1_data_i(32'b0), |
.dmem1_wr_o(), |
.dmem1_rd_o(), |
.dmem1_accept_i(1'b1), |
.dmem1_burst_o(/*open*/), |
.dmem1_sel_o(/*open*/), |
.dmem1_we_o(/*open*/), |
.dmem1_stb_o(/*open*/), |
.dmem1_cyc_o(/*open*/), |
.dmem1_cti_o(/*open*/), |
.dmem1_stall_i(1'b0), |
.dmem1_ack_i(1'b1), |
|
// Data Memory 2 (0x12000000 - 0x12FFFFFF) |
163,11 → 180,13
.dmem2_addr_o(soc_addr), |
.dmem2_data_o(soc_data_w), |
.dmem2_data_i(soc_data_r), |
.dmem2_wr_o(soc_wr), |
.dmem2_rd_o(soc_rd), |
.dmem2_accept_i(1'b1), |
.dmem2_burst_o(/*open*/), |
.dmem2_ack_i(1'b1) |
.dmem2_sel_o(/*open*/), |
.dmem2_we_o(soc_we), |
.dmem2_stb_o(soc_stb), |
.dmem2_cyc_o(/*open*/), |
.dmem2_cti_o(/*open*/), |
.dmem2_stall_i(1'b0), |
.dmem2_ack_i(soc_ack) |
); |
|
// CPU SOC |
190,38 → 209,9
.io_addr_i(soc_addr), |
.io_data_i(soc_data_w), |
.io_data_o(soc_data_r), |
.io_wr_i(soc_wr), |
.io_rd_i(soc_rd) |
.io_we_i(soc_we), |
.io_stb_i(soc_stb), |
.io_ack_o(soc_ack) |
); |
|
// Ack |
always @(posedge clk_i or posedge rst_i) |
begin |
if (rst_i == 1'b1) |
begin |
imem_req_r <= 1'b0; |
end |
else |
begin |
imem_req_r <= imem_rd; |
end |
end |
|
assign imem_ack = imem_req_r; |
|
// Ack |
always @(posedge clk_i or posedge rst_i) |
begin |
if (rst_i == 1'b1) |
begin |
dmem_req_r <= 1'b0; |
end |
else |
begin |
dmem_req_r <= dmem_rd | (|dmem_wr); |
end |
end |
|
assign dmem_ack = dmem_req_r; |
|
endmodule |
/rtl/sim/ram_dp8.v
1,3 → 1,39
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// Module: ram_dp8 - dual port block RAM |
/rtl/peripheral/intr_periph.v
65,8 → 65,8
addr_i, |
data_o, |
data_i, |
wr_i, |
rd_i |
we_i, |
stb_i |
); |
|
//----------------------------------------------------------------- |
94,8 → 94,8
input [7:0] addr_i /*verilator public*/; |
output [31:0] data_o /*verilator public*/; |
input [31:0] data_i /*verilator public*/; |
input [3:0] wr_i /*verilator public*/; |
input rd_i /*verilator public*/; |
input we_i /*verilator public*/; |
input stb_i /*verilator public*/; |
|
//----------------------------------------------------------------- |
// Registers / Wires |
175,7 → 175,7
intr_o <= ((v_irq_status & irq_mask) != {(INTERRUPT_COUNT){1'b0}}) ? 1'b1 : 1'b0; |
|
// Write Cycle |
if (wr_i != 4'b0000) |
if (we_i & stb_i) |
begin |
case (addr_i) |
|
198,33 → 198,22
//----------------------------------------------------------------- |
// Peripheral Register Read |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
always @ * |
begin |
if (rst_i == 1'b1) |
begin |
data_o <= 32'h00000000; |
end |
else |
begin |
// Read cycle? |
if (rd_i == 1'b1) |
begin |
case (addr_i[7:0]) |
case (addr_i[7:0]) |
|
`IRQ_MASK_SET : |
data_o <= {{(32-INTERRUPT_COUNT){1'b0}}, irq_mask}; |
`IRQ_MASK_SET : |
data_o = {{(32-INTERRUPT_COUNT){1'b0}}, irq_mask}; |
|
`IRQ_MASK_CLR : |
data_o <= {{(32-INTERRUPT_COUNT){1'b0}}, irq_mask}; |
`IRQ_MASK_CLR : |
data_o = {{(32-INTERRUPT_COUNT){1'b0}}, irq_mask}; |
|
`IRQ_STATUS : |
data_o <= {{(32-INTERRUPT_COUNT){1'b0}}, irq_status}; |
`IRQ_STATUS : |
data_o = {{(32-INTERRUPT_COUNT){1'b0}}, irq_status}; |
|
default : |
data_o <= 32'h00000000; |
endcase |
end |
end |
default : |
data_o = 32'h00000000; |
endcase |
end |
|
endmodule |
/rtl/peripheral/timer_periph.v
57,8 → 57,8
addr_i, |
data_o, |
data_i, |
wr_i, |
rd_i |
we_i, |
stb_i |
); |
|
//----------------------------------------------------------------- |
81,8 → 81,8
input [7:0] addr_i /*verilator public*/; |
output [31:0] data_o /*verilator public*/; |
input [31:0] data_i /*verilator public*/; |
input [3:0] wr_i /*verilator public*/; |
input rd_i /*verilator public*/; |
input we_i /*verilator public*/; |
input stb_i /*verilator public*/; |
|
//----------------------------------------------------------------- |
// Registers / Wires |
231,7 → 231,7
else |
begin |
// Write Cycle |
if (wr_i != 4'b0000) |
if (we_i & stb_i) |
begin |
case (addr_i) |
|
248,32 → 248,21
//----------------------------------------------------------------- |
// Peripheral Register Read |
//----------------------------------------------------------------- |
always @ (posedge rst_i or posedge clk_i ) |
always @ * |
begin |
if (rst_i == 1'b1) |
begin |
data_o <= 32'h00000000; |
end |
else |
begin |
// Read cycle? |
if (rd_i == 1'b1) |
begin |
case (addr_i[7:0]) |
case (addr_i[7:0]) |
|
// 32-bit systick/1ms counter |
`TIMER_SYSTICK_VAL : |
data_o <= systick_count; |
// 32-bit systick/1ms counter |
`TIMER_SYSTICK_VAL : |
data_o = systick_count; |
|
// Hi res timer (clock rate) |
`TIMER_HIRES : |
data_o <= hr_timer_cnt; |
// Hi res timer (clock rate) |
`TIMER_HIRES : |
data_o = hr_timer_cnt; |
|
default : |
data_o <= 32'h00000000; |
endcase |
end |
end |
default : |
data_o = 32'h00000000; |
endcase |
end |
|
endmodule |