And another attempt to use MMU
Posted: Mon May 30, 2016 7:36 am
Here my 5 cents about a 6502 System with MMU
after reading several threads and solutions of systems using some sort of MMU I thought it would be cool to build a system with a MMU. I'm perfectly aware that having a MMU
with a 6502 is only of academic interest and the 6502 is far away from supporting virtual memory. So this project is pure fun and interest in the subject.
Here is a draft if what I'm about to design. An MMU can serve several functions but I will restrict myself to
- virtual address
- kernel protection
- write protect pages (although in the first release it will only disable writes but no further actions are planned)
I will not use the MMU to support non-resident pages, RAM is cheap and the support for this is beyond this project. I will however consider the following features for a later design using a 65C816.
- abort on write protected pages
- abort on pages that are marked as no execute
I have decided to use a 74LS610 as the MMU. The reason I will use this device is that it is well known, simple, available in DIP and requires only very little GLUE. The maximal
supported memory will be 1Mbyte however I will start with a single 512kbyte SRAM. I will only use 8-bits of the mapping registers for the phyiscal address extensions. The
other 4 bits will be used to implement write protected (WP) pages and pages marked as no execute (NX). WP will be bit 11 of the MMU register and NX will be bit 10.
Principle of operation
After a reset the MMU is disabled (pass-through) and the system will present the following memory map
$0000..$DFFF RAM
$E000..$EFFF IO
$FFFF..$FFFF ROM
All the RAM is write enabled and execute enabled (WP=NX=0 as is the case in pass-through mode). IO is devided into 16 pages.
$E000..$E0FF MMU
$E100..$E1FF Console using a CDP6551 ACIA, I use this as all my ROM images with Monitor use this hardware, just to make my life easy
$E200..$E2FF UART (one of the famous Siemens UART with FIFO and multiple channels that BDD always praises)
$E300..$E3FF 8-bit IDE (CF-Cards support a 8-bit data mode)
$E400..$EFFF free for future use
The ROM will just contain a small monitor using the console together with a small boot-loader.
The major drawback of the 6502 and the 74LS610 is that they do not have a "support" to completely separate "user" and "kernel" mode. That is the 6502 does not
have a dedicated kernal stack-pointer and the 74LS610 has only one set of registers. On the other hand the WD65C02 has a nice feature, the VPB output that
is asserted when the processor reads a vector address. I will use this signal to reset the MMU enable flip-flop. So whenever the CPU reads a vector the MMU
is disabled. Also WP and NX bits will no longer be honored.
So whenever an IRQ, RES, BRK or NMI occurs the User PS and User PC (not in case of RES of course) are saved on the stack in the user address space,
the MMU is switched off and the vector is read from the ROM. Of course they point to some location in RAM (except for the RES vector), where previously
the interrupt handlers have been installed. Then we will store the user context and prepare Kernal mode.
STA USRA
STX USRX
STY USRY
TSX
STX USRX
LDX #KERNALSTACK
TXS
CLD and so on....
If required the MMU can be reactivated and the memory can be mapped to read whatever is required. To return to the usermode the following will
have to be done
- disable the MMU (in "kernal" mode the MMU can be switched on and off under program control)
- load MMU registers with user mapping of corresponding user task
- load the user context
- trigger MMU activation
- execute a RTI
The MMU trigger will delay activation of the MMU by two cycles. So the RTI is still fetched from the "kernel" mode but restoring the PC and PS is done
using the "user" mode with the "user" memory map and the PC and PS will be fetched from the "user" stack.
"user" mapping will typically only map RAM, the only way for a "user" program to exit is using the "BRK" instruction. "NMI" will take care of the
task scheduling and even if a program disables the interrupts (what it should normally not do without asking the "kernal" for permission) will give
the kernal the chance to correct things (e.g. check for pending interrupts, enable interrupts for the "user" program, switch the task etc.)
Of course a 65C816 would have further possiblities like additional vectors (COP) and the possibility to ABORT the instruction. On the other hand
a "kernel" needs to come up with additional support for NATIVE/EMULATION mode and 8/16-bit register mode.
Cheers
Peter
after reading several threads and solutions of systems using some sort of MMU I thought it would be cool to build a system with a MMU. I'm perfectly aware that having a MMU
with a 6502 is only of academic interest and the 6502 is far away from supporting virtual memory. So this project is pure fun and interest in the subject.
Here is a draft if what I'm about to design. An MMU can serve several functions but I will restrict myself to
- virtual address
- kernel protection
- write protect pages (although in the first release it will only disable writes but no further actions are planned)
I will not use the MMU to support non-resident pages, RAM is cheap and the support for this is beyond this project. I will however consider the following features for a later design using a 65C816.
- abort on write protected pages
- abort on pages that are marked as no execute
I have decided to use a 74LS610 as the MMU. The reason I will use this device is that it is well known, simple, available in DIP and requires only very little GLUE. The maximal
supported memory will be 1Mbyte however I will start with a single 512kbyte SRAM. I will only use 8-bits of the mapping registers for the phyiscal address extensions. The
other 4 bits will be used to implement write protected (WP) pages and pages marked as no execute (NX). WP will be bit 11 of the MMU register and NX will be bit 10.
Principle of operation
After a reset the MMU is disabled (pass-through) and the system will present the following memory map
$0000..$DFFF RAM
$E000..$EFFF IO
$FFFF..$FFFF ROM
All the RAM is write enabled and execute enabled (WP=NX=0 as is the case in pass-through mode). IO is devided into 16 pages.
$E000..$E0FF MMU
$E100..$E1FF Console using a CDP6551 ACIA, I use this as all my ROM images with Monitor use this hardware, just to make my life easy
$E200..$E2FF UART (one of the famous Siemens UART with FIFO and multiple channels that BDD always praises)
$E300..$E3FF 8-bit IDE (CF-Cards support a 8-bit data mode)
$E400..$EFFF free for future use
The ROM will just contain a small monitor using the console together with a small boot-loader.
The major drawback of the 6502 and the 74LS610 is that they do not have a "support" to completely separate "user" and "kernel" mode. That is the 6502 does not
have a dedicated kernal stack-pointer and the 74LS610 has only one set of registers. On the other hand the WD65C02 has a nice feature, the VPB output that
is asserted when the processor reads a vector address. I will use this signal to reset the MMU enable flip-flop. So whenever the CPU reads a vector the MMU
is disabled. Also WP and NX bits will no longer be honored.
So whenever an IRQ, RES, BRK or NMI occurs the User PS and User PC (not in case of RES of course) are saved on the stack in the user address space,
the MMU is switched off and the vector is read from the ROM. Of course they point to some location in RAM (except for the RES vector), where previously
the interrupt handlers have been installed. Then we will store the user context and prepare Kernal mode.
STA USRA
STX USRX
STY USRY
TSX
STX USRX
LDX #KERNALSTACK
TXS
CLD and so on....
If required the MMU can be reactivated and the memory can be mapped to read whatever is required. To return to the usermode the following will
have to be done
- disable the MMU (in "kernal" mode the MMU can be switched on and off under program control)
- load MMU registers with user mapping of corresponding user task
- load the user context
- trigger MMU activation
- execute a RTI
The MMU trigger will delay activation of the MMU by two cycles. So the RTI is still fetched from the "kernel" mode but restoring the PC and PS is done
using the "user" mode with the "user" memory map and the PC and PS will be fetched from the "user" stack.
"user" mapping will typically only map RAM, the only way for a "user" program to exit is using the "BRK" instruction. "NMI" will take care of the
task scheduling and even if a program disables the interrupts (what it should normally not do without asking the "kernal" for permission) will give
the kernal the chance to correct things (e.g. check for pending interrupts, enable interrupts for the "user" program, switch the task etc.)
Of course a 65C816 would have further possiblities like additional vectors (COP) and the possibility to ABORT the instruction. On the other hand
a "kernel" needs to come up with additional support for NATIVE/EMULATION mode and 8/16-bit register mode.
Cheers
Peter