|
|
|
@ -1,14 +1,25 @@ |
|
|
|
|
package hal |
|
|
|
|
|
|
|
|
|
const PageSize = 1024 |
|
|
|
|
|
|
|
|
|
var defaultRegister uint16 = 0 |
|
|
|
|
|
|
|
|
|
type Page struct { |
|
|
|
|
Referenced bool |
|
|
|
|
PageNumber uint16 |
|
|
|
|
RegisterAddress *uint16 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type PageTable []*Page |
|
|
|
|
// PageTable uses key as page number
|
|
|
|
|
type PageTable map[uint16]*Page |
|
|
|
|
|
|
|
|
|
type Address uint16 |
|
|
|
|
|
|
|
|
|
type MMU struct { |
|
|
|
|
PageTable *PageTable |
|
|
|
|
LoadedPages []*Page |
|
|
|
|
Registers []float64 // 4k registers
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (address Address) PageNumber() uint16 { |
|
|
|
|
return uint16(address) >> 10 |
|
|
|
|
} |
|
|
|
@ -17,14 +28,55 @@ func (address Address) Offset() uint16 { |
|
|
|
|
return uint16(address) & 0x03FF |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (table *PageTable) Find(address Address) { |
|
|
|
|
func (table PageTable) Find(address Address) { |
|
|
|
|
// 10 bit for one register in a page
|
|
|
|
|
// 6 bit to address the page
|
|
|
|
|
// 000010 | 0000000011
|
|
|
|
|
// -> Page 2, offset 3
|
|
|
|
|
|
|
|
|
|
// Find the page with that number
|
|
|
|
|
page := table[address.PageNumber()] |
|
|
|
|
|
|
|
|
|
// Page not loaded in "physical" register
|
|
|
|
|
if page.RegisterAddress == nil { |
|
|
|
|
// Page Error
|
|
|
|
|
// TODO: Logging
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (mmu *MMU) Load(page *Page) { |
|
|
|
|
if len(mmu.LoadedPages) >= 4 { |
|
|
|
|
for index, loadedPage := range mmu.LoadedPages { |
|
|
|
|
if loadedPage.Referenced { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
loadedPage.RegisterAddress = nil |
|
|
|
|
mmu.LoadedPages = append(mmu.LoadedPages[:index], mmu.LoadedPages[index+1:]...) |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Everything is referenced, we need to remove one
|
|
|
|
|
if len(mmu.LoadedPages) == 4 { |
|
|
|
|
mmu.LoadedPages = mmu.LoadedPages[:2] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
page.RegisterAddress = mmu.findEmptyRegisterAddress() |
|
|
|
|
|
|
|
|
|
mmu.LoadedPages = append(mmu.LoadedPages, page) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (mmu *MMU) findEmptyRegisterAddress() *uint16 { |
|
|
|
|
var i uint16 |
|
|
|
|
for i = 0; i < uint16(len(mmu.Registers)/PageSize); i++ { |
|
|
|
|
for _, loadedPage := range mmu.LoadedPages { |
|
|
|
|
if *loadedPage.RegisterAddress == i { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
return &i |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check if it is already loaded
|
|
|
|
|
// Load it if not
|
|
|
|
|
return &defaultRegister |
|
|
|
|
} |
|
|
|
|