blob: b27fca11a604eacdc3fc29d6db31bea1e616d514 [file] [log] [blame]
// SPDX-FileCopyrightText: 2022 Piotr Wegrzyn
//
// 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.
// SPDX-License-Identifier: Apache-2.0
`include "config.v"
`define PC_ADDR_W 16 // incremented by 2
`define OUT_ADDR_W 24
module immu (
`ifdef USE_POWER_PINS
inout vccd1,
inout vssd1,
`endif
input i_clk,
input i_rst,
input [`PC_ADDR_W-1:0] i_addr,
output [`OUT_ADDR_W-1:0] o_addr,
input [`RW-1:0] i_sr_addr,
input [`RW-1:0] i_sr_data,
input i_sr_we,
input [`OUT_ADDR_W-`PC_ADDR_W-1:0] i_long_high_addr,
input c_long_mode,
input c_pag_en
);
`define OFF_W 12
`define PAGE_IDX_W 4
`define PAGE_ENTRIES 16
`define PAGE_RES_SIZE 12
`define SR_ADDR_OFF `RW'h100
wire [`OFF_W-1:0] page_off = i_addr[`OFF_W-1:0];
wire [`PAGE_IDX_W-1:0] page_idx = i_addr[`OFF_W+`PAGE_IDX_W-1:`OFF_W];
reg [`PAGE_RES_SIZE-1:0] page_table [`PAGE_ENTRIES-1:0];
wire [`PAGE_RES_SIZE-1:0] page_res = {1'b1, page_table[page_idx][`PAGE_RES_SIZE-2:0]};
wire [`RW-1:0] sr_addr_idx = i_sr_addr-`SR_ADDR_OFF;
wire addr_in_range = (i_sr_addr >= `SR_ADDR_OFF) && (i_sr_addr < `SR_ADDR_OFF+16);
reg [7:0] high_addr_off;
always @(posedge i_clk) begin
if (i_rst) begin
page_table[0] <= `PAGE_RES_SIZE'h7fe;
page_table[1] <= `PAGE_RES_SIZE'h7ff;
page_table[2] <= `PAGE_RES_SIZE'b0;
page_table[3] <= `PAGE_RES_SIZE'b0;
page_table[4] <= `PAGE_RES_SIZE'b0;
page_table[5] <= `PAGE_RES_SIZE'b0;
page_table[6] <= `PAGE_RES_SIZE'b0;
page_table[7] <= `PAGE_RES_SIZE'b0;
page_table[8] <= `PAGE_RES_SIZE'b0;
page_table[9] <= `PAGE_RES_SIZE'b0;
page_table[10] <= `PAGE_RES_SIZE'b0;
page_table[11] <= `PAGE_RES_SIZE'b0;
page_table[12] <= `PAGE_RES_SIZE'b0;
page_table[13] <= `PAGE_RES_SIZE'b0;
page_table[14] <= `PAGE_RES_SIZE'b0;
page_table[15] <= `PAGE_RES_SIZE'b0;
end else if (i_sr_we & addr_in_range)
page_table[sr_addr_idx[`PAGE_IDX_W-1:0]] <= i_sr_data[`PAGE_RES_SIZE-1:0];
else if (i_sr_we & i_sr_addr == `SR_ADDR_OFF+16)
high_addr_off <= i_sr_data[7:0];
end
`define PAGE_DEFAULT_PREFIX 8'h80
wire [`OUT_ADDR_W-1:0] page_disable_address = {`PAGE_DEFAULT_PREFIX, i_addr[`RW-1:0]};
wire [`OUT_ADDR_W-1:0] page_enable_address = {page_res, page_off};
wire [`OUT_ADDR_W-1:0] long_mode_addr = {i_long_high_addr+high_addr_off, i_addr};
assign o_addr = c_long_mode ? long_mode_addr : (c_pag_en ? page_enable_address : page_disable_address);
endmodule
`undef OFF_W
`undef PAGE_IDX_W
`undef PAGE_ENTRIES
`undef PAGE_RES_SIZE
`undef SR_ADDR_OFF
`undef PAGE_DEFAULT_PREFIX