Thanks to Stephen Leary (TerribleFire) , a semi some sample code for how the internal works of the MMU. I presume this is in verilog format, and not really familiar with this, but the least it should give a starting point as to what is going on..
Code: Select all
`timescale 1ns / 1ps
/*
Copyright (c) 2012, Stephen J. Leary
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
module mmu(
input CLK_I,
input RST_I,
// cpu wishbone bus
input CPU_STB,
input CPU_CYC,
input CPU_WE,
input [3:0] CPU_SEL,
input [2:0] CPU_FC,
output CPU_ACK,
output CPU_ERR,
output CPU_RTY,
input [31:0] CPU_ADR,
input [31:0] CPU_DAT_I,
output [31:0] CPU_DAT_O,
output [2:0] CPU_IPL,
// shifter wishbone bus
output SFT_STB,
output SFT_CYC,
output SFT_WE,
output [3:0] SFT_SEL,
input SFT_ACK,
input SFT_ERR,
output [ 7:0] SFT_ADR,
output [31:0] SFT_DAT_O,
input [31:0] SFT_DAT_I,
// blitter wishbone bus
output BLT_STB,
output BLT_CYC,
output BLT_WE,
output [3:0] BLT_SEL,
input BLT_ACK,
input BLT_ERR,
output [ 5:0] BLT_ADR,
output [31:0] BLT_DAT_O,
input [31:0] BLT_DAT_I,
// mfp68901 wishbone bus
output MFP_STB,
output MFP_CYC,
output MFP_WE,
output [3:0] MFP_SEL,
input MFP_ACK,
input MFP_ERR,
output [ 5:0] MFP_ADR,
output [31:0] MFP_DAT_O,
input [31:0] MFP_DAT_I,
input MFP_IRQ_I,
output MFP_IACK_O,
// acia wishbone bus
output ACIA_STB,
output ACIA_CYC,
output ACIA_WE,
output [3:0] ACIA_SEL,
input ACIA_ACK,
input ACIA_ERR,
output [ 2:0] ACIA_ADR,
output [31:0] ACIA_DAT_O,
input [31:0] ACIA_DAT_I,
// mmc wishbone bus
output MMC_STB,
output MMC_CYC,
output MMC_WE,
output [3:0] MMC_SEL,
input MMC_ACK,
input MMC_ERR,
output [31:0] MMC_DAT_O,
input [31:0] MMC_DAT_I,
// ram wishbone bus
output RAM_STB,
output RAM_CYC,
output RAM_WE,
output [3:0] RAM_SEL,
input RAM_ACK,
input RAM_ERR,
output [31:0] RAM_ADR,
output [31:0] RAM_DAT_O,
input [31:0] RAM_DAT_I,
input VBL_IRQ_I,
input HBL_IRQ_I
);
wire ram_enable = mmu_config == 4'hA ? (CPU_ADR[23:0] < 24'h400000) :
mmu_config == 4'h2 ? (CPU_ADR[23:0] < 24'h200000) :
mmu_config == 4'h6 ? (CPU_ADR[23:0] < 24'h280000) :
mmu_config == 4'h5 ? (CPU_ADR[23:0] < 24'h100000) :
mmu_config == 4'h1 ? (CPU_ADR[23:0] < 24'h080000) : 1'b0;
wire cpu_space = (CPU_FC == 3'b111);
wire supervisor_mode = (CPU_FC == 3'b101) | (CPU_FC == 3'b110);
wire acia_enable = {CPU_ADR[23:8]} == {16'hFFFC} && ({CPU_ADR[7:0]} < {8'h04}) && !cpu_space;
wire midi_enable = {CPU_ADR[23:8]} == {16'hFFFC} && ({CPU_ADR[7:0]} < {8'h08}) && !cpu_space && !acia_enable;
wire ide_enable = {CPU_ADR[23:8]} == {16'hF000} && ({CPU_ADR[7:0]} < {8'h40}) && !cpu_space;
wire mmc_enable = {CPU_ADR[23:8]} == {16'hFFFE} && ({CPU_ADR[7:0]} < {8'h04}) && !cpu_space;
wire blt_enable = 1'b0; //{CPU_ADR[23:8]} == {16'hFF8A} && ({CPU_ADR[7:0]} < {8'h40}) && !cpu_space;
wire rtc_enable = {CPU_ADR[23:8]} == {16'hFFFC} && ({CPU_ADR[7:0]} > {8'h20}) && !cpu_space;
wire wd1772_enable = {CPU_ADR[23:8]} == {16'hFF86} & !cpu_space;
wire psg_enable = ({CPU_ADR[23:8]} == {16'hFF88}) & !cpu_space;
wire mfp_enable = {CPU_ADR[23:8]} == {16'hFFFA} & !cpu_space;
wire config_enable = {CPU_ADR[23:0]} == {24'hFF8000} & !cpu_space;
wire overlay_enable = {CPU_ADR[23:3]} == 21'd0 & !cpu_space; // shadow the rom to the first 8 bytes.
wire shifter_enable = {CPU_ADR[23:8]} == {16'hFF82} && ((({CPU_ADR[7:0]} >= {8'h40}) & ({CPU_ADR[7:0]} <= {8'h60})) | ({CPU_ADR[7:0]} <= {8'h0C})) && !cpu_space;
wire rom_enable = (CPU_ADR[23:0] >= 24'hE00000) & (CPU_ADR[23:0] < 24'hF00000) | (CPU_ADR[23:0] >= 24'hFA0000) & (CPU_ADR[23:0] < 24'hFF0000);
wire bank0_enable = !shifter_enable & !overlay_enable & (CPU_ADR[23:0] < 24'h200000) & !cpu_space;
wire bank1_enable = !shifter_enable & !overlay_enable & (CPU_ADR[23:0] < 24'h400000) & !cpu_space;
wire write_error = (overlay_enable | rom_enable) & CPU_WE & !cpu_space;
wire [31:0] cfg_dat;
reg cfg_ack;
reg cfg_err;
reg [ 3:0] mmu_config;
// dummy hardware.
reg psg_ack;
reg psg_err;
reg midi_ack;
reg midi_err;
reg ide_ack;
reg ide_err;
reg bank1_ack;
reg bank1_err;
reg wd1772_ack;
reg wd1772_err;
wire [7:0] int_dat;
wire int_err;
wire int_ack;
wire int_rty;
interrupts MMUINT(
.CLK_I (CLK_I),
.RST_I (RST_I),
.FC_I (CPU_FC),
.ADR_I ({CPU_ADR[4:2]}),
.CYC_I (CPU_CYC),
.STB_I (CPU_STB),
.ACK_O (int_ack),
.ERR_O (int_err),
.RTY_O (int_rty),
.DAT_O (int_dat),
.IPL_O (CPU_IPL),
.MFP_IRQ_I (MFP_IRQ_I),
.MFP_IACK_O (MFP_IACK_O),
.MFP_DAT_I (MFP_DAT_I[7:0]),
.VBL_IRQ_I (VBL_IRQ_I),
.HBL_IRQ_I (HBL_IRQ_I)
);
always @(posedge CLK_I) begin
cfg_ack <= 1'b0;
cfg_err <= 1'b0;
psg_ack <= 1'b0;
psg_err <= 1'b0;
midi_ack <= 1'b0;
midi_err <= 1'b0;
ide_ack <= 1'b0;
ide_err <= 1'b0;
bank1_ack <= 1'b0;
bank1_err <= 1'b0;
wd1772_ack <= 1'b0;
wd1772_err <= 1'b0;
if (RST_I) begin
mmu_config <= 4'd2;
cfg_err <= 1'b1;
psg_err <= 1'b1;
midi_err <= 1'b1;
ide_err <= 1'b1;
wd1772_err <= 1'b1;
end else begin
if (config_enable) begin
if (!cfg_ack & CPU_STB & CPU_CYC & (CPU_ADR[7:0] == 8'd0) & CPU_SEL[2] == 1'b1) begin
if (CPU_WE) begin
mmu_config <= CPU_DAT_I[19:16];
end
cfg_ack <= 1'b1;
end
end else if (ide_enable & CPU_STB & CPU_CYC & !ide_ack) begin
ide_ack <= 1'b1;
end else if (midi_enable & CPU_STB & CPU_CYC & !midi_ack) begin
midi_ack <= 1'b1;
end else if (psg_enable & CPU_STB & CPU_CYC & !psg_ack) begin
psg_ack <= 1'b1;
end else if (wd1772_enable & CPU_STB & CPU_CYC & !wd1772_ack) begin
wd1772_ack <= 1'b1;
end else if (bank1_enable & CPU_STB & CPU_CYC & !bank1_ack) begin
bank1_ack <= 1'b1;
end
end
end
assign RAM_CYC = (bank0_enable | rom_enable | overlay_enable) & CPU_CYC & !write_error;
assign RAM_STB = (bank0_enable | rom_enable | overlay_enable) & CPU_STB & !write_error;
assign RAM_WE = bank0_enable & CPU_WE & !write_error;
assign RAM_ADR = bank0_enable ? {12'd0,CPU_ADR[20:0]} :
overlay_enable ? {16'hE000, CPU_ADR[7:0]} : {8'd0,CPU_ADR[23:0]};
assign RAM_SEL = CPU_SEL;
assign RAM_DAT_O = CPU_DAT_I;
assign SFT_CYC = shifter_enable & CPU_CYC;
assign SFT_STB = shifter_enable & CPU_STB;
assign SFT_WE = shifter_enable & CPU_WE;
assign SFT_ADR = CPU_ADR[7:0];
assign SFT_SEL = CPU_SEL;
assign SFT_DAT_O = CPU_DAT_I;
assign BLT_CYC = blt_enable & CPU_CYC;
assign BLT_STB = blt_enable & CPU_STB;
assign BLT_WE = blt_enable & CPU_WE;
assign BLT_ADR = CPU_ADR[5:0];
assign BLT_SEL = CPU_SEL;
assign BLT_DAT_O = CPU_DAT_I;
assign MFP_CYC = mfp_enable & CPU_CYC;
assign MFP_STB = mfp_enable & CPU_STB;
assign MFP_WE = mfp_enable & CPU_WE;
assign MFP_ADR = CPU_ADR[5:0];
assign MFP_SEL = CPU_SEL;
assign MFP_DAT_O = CPU_DAT_I;
assign ACIA_CYC = acia_enable & CPU_CYC;
assign ACIA_STB = acia_enable & CPU_STB;
assign ACIA_WE = acia_enable & CPU_WE;
assign ACIA_ADR = CPU_ADR[2:0];
assign ACIA_SEL = CPU_SEL;
assign ACIA_DAT_O = CPU_DAT_I;
assign MMC_CYC = mmc_enable & CPU_CYC;
assign MMC_STB = mmc_enable & CPU_STB;
assign MMC_WE = mmc_enable & CPU_WE;
assign MMC_SEL = CPU_SEL;
assign MMC_DAT_O = CPU_DAT_I;
assign CPU_RTY = cpu_space ? int_rty : 1'b0;
// note the mfp needs to see interrupt ack cycles
assign CPU_ACK = cpu_space ? int_ack :
write_error ? 1'b0 :
(bank0_enable | rom_enable | overlay_enable) ? RAM_ACK :
mfp_enable ? MFP_ACK :
shifter_enable ? SFT_ACK :
config_enable ? cfg_ack :
psg_enable ? psg_ack :
acia_enable ? ACIA_ACK :
mmc_enable ? MMC_ACK :
midi_enable ? midi_ack :
ide_enable ? ide_ack :
blt_enable ? 1'b1 :
rtc_enable ? 1'b1 :
wd1772_enable ? wd1772_ack :
bank1_enable ? bank1_ack :
1'b0;
assign CPU_ERR = cpu_space ? int_err :
write_error ? 1'b1 :
(bank0_enable | rom_enable | overlay_enable) ? RAM_ERR :
mfp_enable ? MFP_ERR :
shifter_enable ? SFT_ERR :
config_enable ? cfg_err :
psg_enable ? psg_err :
acia_enable ? ACIA_ERR :
mmc_enable ? MMC_ERR :
midi_enable ? midi_err :
ide_enable ? ide_err :
blt_enable ? 1'b0 :
rtc_enable ? 1'b0 :
wd1772_enable ? wd1772_err :
bank1_enable ? bank1_err :
1'b1;
assign CPU_DAT_O = cpu_space ? {24'd0, int_dat} :
(bank0_enable | rom_enable | overlay_enable) ? RAM_DAT_I :
mfp_enable ? MFP_DAT_I :
shifter_enable ? SFT_DAT_I :
config_enable ? cfg_dat :
acia_enable ? ACIA_DAT_I :
mmc_enable ? MMC_DAT_I :
(rtc_enable | wd1772_enable) ? 32'hFFFF_FFFF :
blt_enable ? BLT_DAT_I :
32'h0000_0000;
assign cfg_dat = {12'd0, mmu_config, 12'd0, mmu_config};
endmodule
`default_nettype wire