|
|
@ -15,6 +15,10 @@ type PageTable map[uint16]*Page |
|
|
|
|
|
|
|
|
|
|
|
type Address uint16 |
|
|
|
type Address uint16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type PageErrorHandler interface { |
|
|
|
|
|
|
|
handlePageError(address Address, write bool) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type MMU struct { |
|
|
|
type MMU struct { |
|
|
|
PageTable PageTable |
|
|
|
PageTable PageTable |
|
|
|
LoadedPages []*Page |
|
|
|
LoadedPages []*Page |
|
|
@ -22,6 +26,8 @@ type MMU struct { |
|
|
|
|
|
|
|
|
|
|
|
// pseudo hard drive which holds all pages
|
|
|
|
// pseudo hard drive which holds all pages
|
|
|
|
drive map[uint16][]float64 |
|
|
|
drive map[uint16][]float64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pageErrorHandler PageErrorHandler |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (address Address) PageNumber() uint16 { |
|
|
|
func (address Address) PageNumber() uint16 { |
|
|
@ -32,7 +38,28 @@ func (address Address) Offset() uint16 { |
|
|
|
return uint16(address) & 0x03FF |
|
|
|
return uint16(address) & 0x03FF |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (mmu *MMU) Find(address Address) { |
|
|
|
func NewMMU(pageErrorHandler PageErrorHandler) *MMU { |
|
|
|
|
|
|
|
pageCount := uint16(PageSize / 16) |
|
|
|
|
|
|
|
drive := make(map[uint16][]float64) |
|
|
|
|
|
|
|
pageTable := make(PageTable) |
|
|
|
|
|
|
|
for i := uint16(0); i < pageCount; i++ { |
|
|
|
|
|
|
|
drive[i] = make([]float64, PageSize, PageSize) |
|
|
|
|
|
|
|
pageTable[i] = &Page{ |
|
|
|
|
|
|
|
Referenced: false, |
|
|
|
|
|
|
|
RegisterAddress: nil, |
|
|
|
|
|
|
|
PageNumber: i, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return &MMU{ |
|
|
|
|
|
|
|
PageTable: pageTable, |
|
|
|
|
|
|
|
LoadedPages: make([]*Page, 0, 4), |
|
|
|
|
|
|
|
Registers: make([]float64, PageSize*4, PageSize*4), |
|
|
|
|
|
|
|
drive: drive, |
|
|
|
|
|
|
|
pageErrorHandler: pageErrorHandler, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (mmu *MMU) Read(address Address) float64 { |
|
|
|
// 10 bit for one register in a page
|
|
|
|
// 10 bit for one register in a page
|
|
|
|
// 6 bit to address the page
|
|
|
|
// 6 bit to address the page
|
|
|
|
// 000010 | 0000000011
|
|
|
|
// 000010 | 0000000011
|
|
|
@ -44,9 +71,30 @@ func (mmu *MMU) Find(address Address) { |
|
|
|
// Page not loaded in "physical" register
|
|
|
|
// Page not loaded in "physical" register
|
|
|
|
if page.RegisterAddress == nil { |
|
|
|
if page.RegisterAddress == nil { |
|
|
|
// Page Error
|
|
|
|
// Page Error
|
|
|
|
// TODO: Logging
|
|
|
|
mmu.pageErrorHandler(address, false) |
|
|
|
|
|
|
|
mmu.Load(page) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
page.Referenced = true |
|
|
|
|
|
|
|
return mmu.Registers[page.RegisterOffset()+int(address.Offset())] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (mmu *MMU) Write(address Address, content float64) { |
|
|
|
|
|
|
|
// 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 := mmu.PageTable[address.PageNumber()] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Page not loaded in "physical" register
|
|
|
|
|
|
|
|
if page.RegisterAddress == nil { |
|
|
|
|
|
|
|
// Page Error
|
|
|
|
|
|
|
|
mmu.pageErrorHandler(address, true) |
|
|
|
|
|
|
|
mmu.Load(page) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
page.Referenced = true |
|
|
|
|
|
|
|
mmu.Registers[page.RegisterOffset()+int(address.Offset())] = content |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -54,6 +102,7 @@ func (mmu *MMU) Load(page *Page) { |
|
|
|
if len(mmu.LoadedPages) >= 4 { |
|
|
|
if len(mmu.LoadedPages) >= 4 { |
|
|
|
for index, loadedPage := range mmu.LoadedPages { |
|
|
|
for index, loadedPage := range mmu.LoadedPages { |
|
|
|
if loadedPage.Referenced { |
|
|
|
if loadedPage.Referenced { |
|
|
|
|
|
|
|
loadedPage.Referenced = false |
|
|
|
continue |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
|
mmu.movePageToDrive(loadedPage) |
|
|
|
mmu.movePageToDrive(loadedPage) |
|
|
@ -91,7 +140,7 @@ func (mmu *MMU) movePageToDrive(page *Page) { |
|
|
|
for i := 0; i < PageSize-1; i++ { |
|
|
|
for i := 0; i < PageSize-1; i++ { |
|
|
|
mmu.drive[page.PageNumber][i] = mmu.Registers[i+page.RegisterOffset()] |
|
|
|
mmu.drive[page.PageNumber][i] = mmu.Registers[i+page.RegisterOffset()] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
page.Referenced = false |
|
|
|
page.RegisterAddress = nil |
|
|
|
page.RegisterAddress = nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|