catalyst-n1 / rtl /rv32im_cluster.v
mrwabbit's picture
Initial upload: Catalyst N1 open source neuromorphic processor RTL
e4cdd5f verified
// ============================================================================
// RV32IM Cluster
// ============================================================================
//
// Copyright 2026 Henry Arthur Shulayev Barnes / Catalyst Neuromorphic Ltd
// Company No. 17054540 — UK Patent Application No. 2602902.6
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ============================================================================
`timescale 1ns/1ps
module rv32im_cluster #(
parameter IMEM_DEPTH = 65536,
parameter IMEM_ADDR_BITS = 16,
parameter DMEM_DEPTH = 65536,
parameter DMEM_ADDR_BITS = 16
)(
input wire clk,
input wire rst_n,
input wire [2:0] enable,
input wire imem_we_0,
input wire [IMEM_ADDR_BITS-1:0] imem_waddr_0,
input wire [31:0] imem_wdata_0,
input wire imem_we_1,
input wire [IMEM_ADDR_BITS-1:0] imem_waddr_1,
input wire [31:0] imem_wdata_1,
input wire imem_we_2,
input wire [IMEM_ADDR_BITS-1:0] imem_waddr_2,
input wire [31:0] imem_wdata_2,
output wire mmio_valid,
output wire mmio_we,
output wire [15:0] mmio_addr,
output wire [31:0] mmio_wdata,
input wire [31:0] mmio_rdata,
input wire mmio_ready,
output wire [2:0] halted,
output wire [31:0] pc_out_0,
output wire [31:0] pc_out_1,
output wire [31:0] pc_out_2
);
wire c0_mmio_valid, c0_mmio_we;
wire [15:0] c0_mmio_addr;
wire [31:0] c0_mmio_wdata;
rv32i_core #(
.IMEM_DEPTH(IMEM_DEPTH), .IMEM_ADDR_BITS(IMEM_ADDR_BITS),
.DMEM_DEPTH(DMEM_DEPTH), .DMEM_ADDR_BITS(DMEM_ADDR_BITS)
) core0 (
.clk(clk), .rst_n(rst_n), .enable(enable[0]),
.imem_we(imem_we_0), .imem_waddr(imem_waddr_0), .imem_wdata(imem_wdata_0),
.mmio_valid(c0_mmio_valid), .mmio_we(c0_mmio_we),
.mmio_addr(c0_mmio_addr), .mmio_wdata(c0_mmio_wdata),
.mmio_rdata(combined_rdata),
.mmio_ready(c0_mmio_valid ? combined_ready : 1'b0),
.halted(halted[0]), .pc_out(pc_out_0),
.debug_bp_addr_0(32'd0), .debug_bp_addr_1(32'd0),
.debug_bp_addr_2(32'd0), .debug_bp_addr_3(32'd0),
.debug_bp_enable(4'd0),
.debug_resume(1'b0), .debug_halt_req(1'b0), .debug_single_step(1'b0)
);
wire c1_mmio_valid, c1_mmio_we;
wire [15:0] c1_mmio_addr;
wire [31:0] c1_mmio_wdata;
wire c1_grant = c1_mmio_valid && !c0_mmio_valid;
rv32i_core #(
.IMEM_DEPTH(IMEM_DEPTH), .IMEM_ADDR_BITS(IMEM_ADDR_BITS),
.DMEM_DEPTH(DMEM_DEPTH), .DMEM_ADDR_BITS(DMEM_ADDR_BITS)
) core1 (
.clk(clk), .rst_n(rst_n), .enable(enable[1]),
.imem_we(imem_we_1), .imem_waddr(imem_waddr_1), .imem_wdata(imem_wdata_1),
.mmio_valid(c1_mmio_valid), .mmio_we(c1_mmio_we),
.mmio_addr(c1_mmio_addr), .mmio_wdata(c1_mmio_wdata),
.mmio_rdata(combined_rdata),
.mmio_ready(c1_grant ? combined_ready : 1'b0),
.halted(halted[1]), .pc_out(pc_out_1),
.debug_bp_addr_0(32'd0), .debug_bp_addr_1(32'd0),
.debug_bp_addr_2(32'd0), .debug_bp_addr_3(32'd0),
.debug_bp_enable(4'd0),
.debug_resume(1'b0), .debug_halt_req(1'b0), .debug_single_step(1'b0)
);
wire c2_mmio_valid, c2_mmio_we;
wire [15:0] c2_mmio_addr;
wire [31:0] c2_mmio_wdata;
wire c2_grant = c2_mmio_valid && !c0_mmio_valid && !c1_mmio_valid;
rv32i_core #(
.IMEM_DEPTH(IMEM_DEPTH), .IMEM_ADDR_BITS(IMEM_ADDR_BITS),
.DMEM_DEPTH(DMEM_DEPTH), .DMEM_ADDR_BITS(DMEM_ADDR_BITS)
) core2 (
.clk(clk), .rst_n(rst_n), .enable(enable[2]),
.imem_we(imem_we_2), .imem_waddr(imem_waddr_2), .imem_wdata(imem_wdata_2),
.mmio_valid(c2_mmio_valid), .mmio_we(c2_mmio_we),
.mmio_addr(c2_mmio_addr), .mmio_wdata(c2_mmio_wdata),
.mmio_rdata(combined_rdata),
.mmio_ready(c2_grant ? combined_ready : 1'b0),
.halted(halted[2]), .pc_out(pc_out_2),
.debug_bp_addr_0(32'd0), .debug_bp_addr_1(32'd0),
.debug_bp_addr_2(32'd0), .debug_bp_addr_3(32'd0),
.debug_bp_enable(4'd0),
.debug_resume(1'b0), .debug_halt_req(1'b0), .debug_single_step(1'b0)
);
reg [31:0] mailbox [0:3];
integer mbi;
wire arb_valid = c0_mmio_valid | c1_mmio_valid | c2_mmio_valid;
wire [15:0] arb_addr = c0_mmio_valid ? c0_mmio_addr :
c1_mmio_valid ? c1_mmio_addr :
c2_mmio_addr;
wire arb_we = c0_mmio_valid ? c0_mmio_we :
c1_mmio_valid ? c1_mmio_we :
c2_mmio_we;
wire [31:0] arb_wdata = c0_mmio_valid ? c0_mmio_wdata :
c1_mmio_valid ? c1_mmio_wdata :
c2_mmio_wdata;
wire is_mailbox = arb_valid && (arb_addr >= 16'h0080) && (arb_addr <= 16'h008C);
wire [1:0] mailbox_idx = arb_addr[3:2];
reg [31:0] mailbox_rdata;
always @(*) begin
mailbox_rdata = mailbox[mailbox_idx];
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (mbi = 0; mbi < 4; mbi = mbi + 1)
mailbox[mbi] <= 32'd0;
end else if (is_mailbox && arb_we) begin
mailbox[mailbox_idx] <= arb_wdata;
end
end
wire mailbox_ready = is_mailbox;
assign mmio_valid = arb_valid && !is_mailbox;
assign mmio_we = arb_we;
assign mmio_addr = arb_addr;
assign mmio_wdata = arb_wdata;
wire [31:0] combined_rdata = is_mailbox ? mailbox_rdata : mmio_rdata;
wire combined_ready = is_mailbox ? mailbox_ready : mmio_ready;
endmodule