Initial commit

This commit is contained in:
Elyan 2024-11-01 11:54:59 +01:00
parent 522c95ea0a
commit 866eebd43d
25 changed files with 976 additions and 3 deletions

View File

@ -9,13 +9,25 @@ SRC := $(shell find . -type f -name '*.go' -print) go.mod go.sum
all: build all: build
.PHONY: build .PHONY: build
build: build-cpusim build: build-cpusim build-asmtest build-simtest
.PHONY: build-cpusim .PHONY: build-cpusim
build-cpusim: $(BINDIR)/cpusim build-cpusim: $(BINDIR)/cpusim
$(BINDIR)/cpusim: $(SRC) $(BINDIR)/cpusim: $(SRC)
go build -trimpath -o $@ ./cmd/cpusim go build -trimpath -o $@ ./cmd/$(@F)
.PHONY: build-asmtest
build-asmtest: $(BINDIR)/asmtest
$(BINDIR)/asmtest: $(SRC)
go build -trimpath -o $@ ./cmd/$(@F)
.PHONY: build-simtest
build-simtest: $(BINDIR)/simtest
$(BINDIR)/simtest: $(SRC)
go build -trimpath -o $@ ./cmd/$(@F)
.PHONY: clean .PHONY: clean
clean: clean:

27
cmd/asmtest/asmtest.go Normal file
View File

@ -0,0 +1,27 @@
package main
import (
"fmt"
"git.elyanpoujol.fr/elyan/central-arch/pkg/cpu"
"git.elyanpoujol.fr/elyan/central-arch/pkg/instr"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simcontext"
)
const (
MOV_r1_r2 instr.Instr = 0xffff_ff2a
SVC_ffffff instr.Instr = 0xffff_ffff
)
func main() {
cpu := cpu.New(simcontext.SimContext{}, nil)
cpu.RegisterInstr(instr.InstrDesc{
Mnemonic: "LDR",
VariantName: "LDRIR",
OpCode: 0x01,
Format: instr.A,
Formatter: func(i *instr.DecodedInstr) string { return "Hello" }})
fmt.Printf("MOV[6:0] = %#0x\n", cpu.GetOpCode(MOV_r1_r2))
fmt.Printf("SVC[6:0] = %#0x\n", cpu.GetOpCode(SVC_ffffff))
}

48
cmd/simtest/main.go Normal file
View File

@ -0,0 +1,48 @@
package main
import (
"log"
"time"
"git.elyanpoujol.fr/elyan/central-arch/pkg/breakcfg"
"git.elyanpoujol.fr/elyan/central-arch/pkg/events"
"git.elyanpoujol.fr/elyan/central-arch/pkg/instrset"
"git.elyanpoujol.fr/elyan/central-arch/pkg/sim"
)
type SysoutEventLogger struct{}
func (l *SysoutEventLogger) Log(e events.SimEvent) {
log.Printf("%v\n", e)
}
func main() {
eventLogger := &SysoutEventLogger{}
simConfig := sim.SimConfig{
RamSize: 64,
UseMMU: false,
UseCache: false,
}
schedulerConfig := sim.SchedulerConfig{BreakableEventConfig: breakcfg.New()}
breakcfg.SetSteppingType[events.CpuDecodedEvent](schedulerConfig.BreakableEventConfig, breakcfg.ALLOW_BREAK)
sim := sim.New(simConfig, schedulerConfig, eventLogger)
sim.RegisterInstructionSet(instrset.CentralInstructionSet)
/*
sim.QueueStateAccess(func(s simstate.SimState) {
s.RamState.Data[0] = 0xdeaddead
})
*/
go func() {
sim.Start()
}()
time.Sleep(5 * time.Second)
sim.Stop()
time.Sleep(time.Second)
}

2
go.mod
View File

@ -1,4 +1,4 @@
module git.elyanpoujol.fr/elyan/cpu module git.elyanpoujol.fr/elyan/central-arch
go 1.23.2 go 1.23.2

91
pkg/breakcfg/breakcfg.go Normal file
View File

@ -0,0 +1,91 @@
package breakcfg
import (
"reflect"
"git.elyanpoujol.fr/elyan/central-arch/pkg/events"
)
type BreakableEventId uint
/*
const (
// CPU events
CPU_FETCH_INSTR_BEGIN BreakableEventId = iota
CPU_FETCH_INSTR_END
CPU_DECODED_INSTR
CPU_EXECUTED_INSTR
CPU_READ_MEM_REQUEST
CPU_WRITE_MEM_REQUEST
CPU_MODE_TRANSITION
// MMU events
MMU_TLB_NEXT_ENTRY
MMU_TLB_HIT
MMU_TLB_MISS
MMU_TLB_EVICT_ENTRY
MMU_TLB_NEW_ENTRY
MMU_WALK_NEXT_ENTRY
MMU_WALK_NEXT_LEVEL
MMU_WALK_HIT
MMU_WALK_MISS
// Cache events
CACHE_STEP_NEXT_ENTRY
CACHE_STEP_HIT
CACHE_STEP_MISS
CACHE_EVICT_ENTRY
CACHE_NEW_ENTRY
// Memory events
MEMORY_READ
MEMORY_WRITE
MEMORY_UNALIGNED_READ
MEMORY_UNALIGNED_WRITE
// Event count, not a real event
BREAKABLE_EVENT_ID_COUNT
)
*/
type SteppingType uint8
const (
ALLOW_BREAK SteppingType = iota // Default value, allow breakpoints for a given event type
ALWAYS_BREAK // Always break even if no breakpoints were set for the event type
IGNORE_BREAK // Ignore the breakpoints for the event type
)
type BreakableEventConfig struct {
eventSteppingTypes map[reflect.Type]SteppingType
}
func New() *BreakableEventConfig {
cfg := &BreakableEventConfig{
eventSteppingTypes: make(map[reflect.Type]SteppingType),
}
cfg.init()
return cfg
}
func SetSteppingType[T events.SimEvent](cfg *BreakableEventConfig, st SteppingType) {
cfg.eventSteppingTypes[key[T]()] = st
}
func GetSteppingType[T events.SimEvent](cfg *BreakableEventConfig) SteppingType {
return cfg.eventSteppingTypes[key[T]()]
}
func (cfg *BreakableEventConfig) init() {
// TODO Add all breakable events
SetSteppingType[events.CpuFetchBeginEvent](cfg, ALLOW_BREAK)
SetSteppingType[events.CpuFetchEndEvent](cfg, ALLOW_BREAK)
SetSteppingType[events.CpuDecodedEvent](cfg, ALLOW_BREAK)
SetSteppingType[events.CpuExecuteEvent](cfg, ALLOW_BREAK)
SetSteppingType[events.CpuReadMemoryBeginEvent](cfg, ALLOW_BREAK)
SetSteppingType[events.CpuReadMemoryEndEvent](cfg, ALLOW_BREAK)
SetSteppingType[events.CpuWriteMemoryBeginEvent](cfg, ALLOW_BREAK)
SetSteppingType[events.CpuWriteMemoryEndEvent](cfg, ALLOW_BREAK)
SetSteppingType[events.CpuModeTransitionEvent](cfg, ALLOW_BREAK)
}
func key[T events.SimEvent]() reflect.Type {
return reflect.TypeFor[T]()
}

25
pkg/cache/cache.go vendored Normal file
View File

@ -0,0 +1,25 @@
package cache
import (
"git.elyanpoujol.fr/elyan/central-arch/pkg/memory"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simcontext"
)
// TODO Add a field of type CacheState
type Cache struct{}
func (c *Cache) Read(addr uint32) (uint32, error) {
panic("Not implemented yet")
}
func (c *Cache) Write(addr uint32, value uint32) error {
panic("Not implemented yet")
}
func (m *Cache) Fetch(addr uint32) (uint32, error) {
panic("Not implemented yet")
}
func New(context simcontext.SimContext, realMemory memory.Memory) *Cache {
panic("Not implemented yet")
}

28
pkg/cpu/cpu.go Normal file
View File

@ -0,0 +1,28 @@
package cpu
import (
"git.elyanpoujol.fr/elyan/central-arch/pkg/events"
"git.elyanpoujol.fr/elyan/central-arch/pkg/memory"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simcontext"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simstate"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simstep"
)
type Cpu struct {
state simstate.CpuState
stepper simstep.SimStepper
eventLogger events.EventLogger
memory memory.Memory
}
func New(context simcontext.SimContext, memory memory.Memory) *Cpu {
return &Cpu{
stepper: context.Stepper,
eventLogger: context.EventLogger,
memory: memory,
}
}
func (c *Cpu) State() *simstate.CpuState {
return &c.state
}

33
pkg/cpu/exec.go Normal file
View File

@ -0,0 +1,33 @@
package cpu
import (
"sync"
"git.elyanpoujol.fr/elyan/central-arch/pkg/events"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simstep"
)
func (cpu *Cpu) Run(wg *sync.WaitGroup) {
wg.Add(1)
defer wg.Done()
// TODO Implement CPU
var err error
for err == nil {
event := &events.DebugEvent{Msg: "Will step"}
cpu.eventLogger.Log(event)
err = cpu.stepper.RequestStep(event)
if err != nil {
if err != simstep.SimQuitRequest {
panic(err)
}
cpu.eventLogger.Log(&events.DebugEvent{Msg: "Scheduler quit requested"})
} else {
cpu.eventLogger.Log(&events.DebugEvent{Msg: "After step"})
}
}
}

26
pkg/cpu/instr.go Normal file
View File

@ -0,0 +1,26 @@
package cpu
import (
"log"
"git.elyanpoujol.fr/elyan/central-arch/pkg/instr"
)
const instrMask = 0x7f
func (cpu *Cpu) RegisterInstr(instrDesc instr.InstrDesc) {
// TODO Implement it
log.Printf("Registered: %+v\n", instrDesc)
}
func (cpu *Cpu) GetOpCode(i instr.Instr) uint32 {
return uint32(i & instrMask)
}
func (cpu *Cpu) GetFormat(i instr.Instr) instr.InstrFormat {
panic("Not implemented yet")
}
func (cpu *Cpu) Decode(i instr.Instr, decodedInstr *instr.DecodedInstr) {
panic("Not implemented yet")
}

66
pkg/events/events.go Normal file
View File

@ -0,0 +1,66 @@
package events
import (
"git.elyanpoujol.fr/elyan/central-arch/pkg/modes"
)
type SimEvent interface{}
type DebugEvent struct {
Msg string
}
func (de *DebugEvent) String() string {
return de.Msg
}
type CpuFetchBeginEvent struct {
Addr uint32
}
type CpuFetchEndEvent struct {
Addr uint32
Value uint32
}
type CpuDecodedEvent struct {
Addr uint32
InstrValue uint32
InstrString string
}
type CpuExecuteEvent struct {
Addr uint32
InstrValue uint32
InstrString string
}
type CpuReadMemoryBeginEvent struct {
Addr uint32
}
type CpuReadMemoryEndEvent struct {
Addr uint32
Value uint32
}
type CpuWriteMemoryBeginEvent struct {
Addr uint32
Value uint32
}
type CpuWriteMemoryEndEvent struct {
Addr uint32
Value uint32
}
type CpuModeTransitionEvent struct {
Prev modes.CpuMode
Next modes.CpuMode
}
// TODO Add more events
type EventLogger interface {
Log(e SimEvent)
}

101
pkg/instr/instr.go Normal file
View File

@ -0,0 +1,101 @@
package instr
import (
"git.elyanpoujol.fr/elyan/central-arch/pkg/register"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simstate"
)
type Instr uint32
type InstrFormat uint32
const (
A InstrFormat = iota
B
C
D1
D2
E
)
func (instrf InstrFormat) String() string {
switch instrf {
case A:
return "A"
case B:
return "B"
case C:
return "C"
case D1:
return "D1"
case D2:
return "D2"
case E:
return "E"
}
panic("unknown format")
}
type Cond uint32
const (
AL Cond = iota // Always
EQ // Equal, Z==1
NEQ // Not Equal, Z==0
UGE // Unsigned Greater or Equal, C==1
CS Cond = iota - 1 // Carry Set, C==1
ULT // Unsigned Lower Than, C==0
CC Cond = iota - 2 // Carry Clear, C==0
NEG // Negative, N==1
POS // Positive, N==0
VS // oVerflow Set, V==1
VC // oVerflow Clear, V==0
UGT // Unsigned Greater Than, C==1 && Z==0
ULE // Unsigned Lower Than, C==0 && Z==1
SGE // Signed Greater or Equal, N==V
SLT // Signed Lower Than, N!=V
SGT // Signed Greater Than, Z==0 && N==V
SLE // Signed Lower or Equal, Z==1 && N!=V
)
type InstrFormatter func(*DecodedInstr) string
type InstrBehavior func(*DecodedInstr, simstate.SimState) error
type InstrDesc struct {
VariantName string
Mnemonic string
OpCode uint32
Format InstrFormat
Formatter InstrFormatter
Behavior InstrBehavior
}
type StandardFormatFields struct {
Condition Cond
Rd register.CpuRegister
Rs1 register.CpuRegister
Rs2 register.CpuRegister
Imm uint32
}
type SubsystemFormatFields struct {
Reg register.CpuRegister
Sid uint32
Sre uint32
Cmd uint32
}
type DecodedInstr struct {
Format InstrFormat
OpCode uint32
// A, B, C, D1 and D2 formats fields
StandardFormatFields
// E format fields
SubsystemFormatFields
}

14
pkg/instrset/Instrset.go Normal file
View File

@ -0,0 +1,14 @@
package instrset
import "git.elyanpoujol.fr/elyan/central-arch/pkg/instr"
var CentralInstructionSet = []instr.InstrDesc{
{VariantName: "NOP", Mnemonic: "nop", OpCode: 0x0, Format: instr.D2, Formatter: nil, Behavior: nil},
{VariantName: "LDRIR", Mnemonic: "ldr", OpCode: 0x1, Format: instr.A, Formatter: nil, Behavior: nil},
{VariantName: "LDRIRW", Mnemonic: "ldr", OpCode: 0x2, Format: instr.A, Formatter: nil, Behavior: nil},
{VariantName: "LDRIOW", Mnemonic: "ldr", OpCode: 0x3, Format: instr.A, Formatter: nil, Behavior: nil},
{VariantName: "LDRR", Mnemonic: "ldr", OpCode: 0x4, Format: instr.A, Formatter: nil, Behavior: nil},
{VariantName: "LDRRW", Mnemonic: "ldr", OpCode: 0x5, Format: instr.A, Formatter: nil, Behavior: nil},
{VariantName: "LDROW", Mnemonic: "ldr", OpCode: 0x6, Format: instr.A, Formatter: nil, Behavior: nil},
{VariantName: "SVC", Mnemonic: "svc", OpCode: 0x7f, Format: instr.D2, Formatter: nil, Behavior: nil},
}

7
pkg/memory/memory.go Normal file
View File

@ -0,0 +1,7 @@
package memory
type Memory interface {
Read(addr uint32) (uint32, error)
Write(addr uint32, value uint32) error
Fetch(addr uint32) (uint32, error)
}

25
pkg/mmu/mmu.go Normal file
View File

@ -0,0 +1,25 @@
package mmu
import (
"git.elyanpoujol.fr/elyan/central-arch/pkg/memory"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simcontext"
)
// TODO Add a field of type MmuState
type MMU struct{}
func (m *MMU) Read(addr uint32) (uint32, error) {
panic("Not implemented yet")
}
func (m *MMU) Write(addr uint32, value uint32) error {
panic("Not implemented yet")
}
func (m *MMU) Fetch(addr uint32) (uint32, error) {
panic("Not implemented yet")
}
func New(context simcontext.SimContext, realMemory memory.Memory) *MMU {
panic("Not implemented yet")
}

16
pkg/modes/modes.go Normal file
View File

@ -0,0 +1,16 @@
package modes
type CpuMode uint
const (
USER CpuMode = iota
SUPERVISOR
FAULT
)
type CpuPrivilegeLevel uint
const (
UNPRIVILEGED CpuPrivilegeLevel = iota
PRIVILEGED
)

52
pkg/ram/ram.go Normal file
View File

@ -0,0 +1,52 @@
package ram
import (
"errors"
"fmt"
"git.elyanpoujol.fr/elyan/central-arch/pkg/events"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simcontext"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simstate"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simstep"
)
type RAM struct {
state simstate.RamState
stepper simstep.SimStepper
eventLogger events.EventLogger
}
const alignment = 4
func New(context simcontext.SimContext, bytes uint) (*RAM, error) {
if bytes < alignment {
return nil, errors.New("memory size should be at least 4 bytes")
}
return &RAM{
state: simstate.RamState{Data: make([]uint32, bytes/alignment)},
stepper: context.Stepper,
eventLogger: context.EventLogger,
}, nil
}
func (r *RAM) Read(addr uint32) (uint32, error) {
if addr%alignment != 0 {
return 0, fmt.Errorf("unaligned memory address: %08x", addr)
}
return r.state.Data[addr/alignment], nil
}
func (r *RAM) Write(addr uint32, value uint32) error {
if addr%alignment != 0 {
return fmt.Errorf("unaligned memory address: %08x", addr)
}
r.state.Data[addr/alignment] = value
return nil
}
func (m *RAM) Fetch(addr uint32) (uint32, error) {
return m.Read(addr)
}

33
pkg/register/register.go Normal file
View File

@ -0,0 +1,33 @@
package register
type CpuRegister uint32
type CpuStatusRegister uint32
const (
R0 CpuRegister = iota
R1
R2
R3
R4
R5
R6
R7
LR CpuRegister = iota + 15
PC
SP
PC_USER
SP_USER
PC_SYS
SP_SYS
PC_FAULT
SP_FAULT
)
// General purpose registers count
const GPR_COUNT = 8
const (
PSR CpuStatusRegister = iota
ESR_SVC
ESR_FAULT
)

30
pkg/sim/breakpoint.go Normal file
View File

@ -0,0 +1,30 @@
package sim
type CpuBreakpoint struct {
Addr uint32
}
type WatchpointType uint
const (
READ WatchpointType = iota
WRITE
READ_WRITE
)
type CpuWatchpoint struct {
Addr uint32
Type WatchpointType
}
type CpuModeTransitionBreakType uint
const (
NONE CpuModeTransitionBreakType = iota
ALL
USER
SUPERVISOR
FAULT
PRIVILEGED
UNPRIVILEGED
)

3
pkg/sim/commands.go Normal file
View File

@ -0,0 +1,3 @@
package sim
type Command interface{}

102
pkg/sim/scheduler.go Normal file
View File

@ -0,0 +1,102 @@
package sim
import (
"log"
"sync"
"time"
"git.elyanpoujol.fr/elyan/central-arch/pkg/breakcfg"
"git.elyanpoujol.fr/elyan/central-arch/pkg/events"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simstep"
)
type SchedulerConfig struct {
BreakableEventConfig *breakcfg.BreakableEventConfig
}
type Scheduler struct {
config SchedulerConfig
cpuBreakpoints map[CpuBreakpoint]bool
cpuWatchpoints map[CpuWatchpoint]bool
cpuModeTransitionBreakType CpuModeTransitionBreakType
stepRequest chan events.SimEvent
stepResponse chan bool
commandRequest chan Command
commandReponse chan bool
breakEvent chan *Sim
quitEvent <-chan bool
}
func NewScheduler(config SchedulerConfig, quitEvent <-chan bool) *Scheduler {
return &Scheduler{
config: config,
cpuBreakpoints: make(map[CpuBreakpoint]bool),
cpuWatchpoints: make(map[CpuWatchpoint]bool),
// When the scheduler stopped running, we don't want the client to block
// when sending to this channel
stepRequest: make(chan events.SimEvent, 1),
stepResponse: make(chan bool),
// When the scheduler stopped running, we don't want the client to block
// when sending to this channel
commandRequest: make(chan Command, 1),
commandReponse: make(chan bool),
breakEvent: make(chan *Sim),
quitEvent: quitEvent,
}
}
func (s *Scheduler) Run(wg *sync.WaitGroup) {
wg.Add(1)
defer wg.Done()
for {
select {
case <-s.quitEvent:
s.closeSendingChannels()
return
case req := <-s.stepRequest:
s.handleStepRequest(req)
case cmd := <-s.commandRequest:
s.handleSchedulingCommand(cmd)
}
}
}
func (s *Scheduler) closeSendingChannels() {
close(s.stepResponse)
close(s.commandReponse)
close(s.breakEvent)
}
func (s *Scheduler) Cleanup() {
close(s.stepRequest)
close(s.commandRequest)
}
func (s *Scheduler) handleStepRequest(req simstep.SimStepRequest) {
// TODO Handle request
// TODO Check breakpoints
log.Println("step !")
time.Sleep(time.Second)
s.stepResponse <- true
}
func (s *Scheduler) handleSchedulingCommand(cmd Command) {
// TODO Handle scheduling command
}
func (s *Scheduler) RequestStep(req simstep.SimStepRequest) error {
s.stepRequest <- req
// The scheduler always sends true, to receive false means that the channel is closed
// and thus, that we must quit
doContinue := <-s.stepResponse
if !doContinue {
return simstep.SimQuitRequest
}
return nil
}

156
pkg/sim/sim.go Normal file
View File

@ -0,0 +1,156 @@
package sim
import (
"sync"
"git.elyanpoujol.fr/elyan/central-arch/pkg/cache"
"git.elyanpoujol.fr/elyan/central-arch/pkg/cpu"
"git.elyanpoujol.fr/elyan/central-arch/pkg/events"
"git.elyanpoujol.fr/elyan/central-arch/pkg/instr"
"git.elyanpoujol.fr/elyan/central-arch/pkg/memory"
"git.elyanpoujol.fr/elyan/central-arch/pkg/mmu"
"git.elyanpoujol.fr/elyan/central-arch/pkg/ram"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simcontext"
)
type SimStatus struct {
sync.Mutex
Started bool
}
type Sim struct {
status SimStatus
config SimConfig
cpu *cpu.Cpu
ram *ram.RAM
cache *cache.Cache
mmu *mmu.MMU
scheduler *Scheduler
simQuitEvent chan bool
schedulerQuitEvent chan<- bool
}
type SimConfig struct {
RamSize uint
UseMMU bool
UseCache bool
}
func New(simConfig SimConfig, schedulerConfig SchedulerConfig, eventLogger events.EventLogger) *Sim {
var cpuMemory memory.Memory
var mmuMemory *mmu.MMU
var cacheMemory *cache.Cache
// We make the channel buffered to not cause wait for the scheduler to read the quit event
// as we also wait on the wait group
schedulerQuitEvent := make(chan bool, 1)
simScheduler := NewScheduler(schedulerConfig, schedulerQuitEvent)
context := simcontext.SimContext{EventLogger: eventLogger, Stepper: simScheduler}
ram, err := ram.New(context, simConfig.RamSize)
// By default, the CPU memory is the RAM
cpuMemory = ram
if simConfig.UseMMU && !simConfig.UseCache {
// Wrap the RAM behind MMU
mmuMemory = mmu.New(context, ram)
cpuMemory = mmuMemory
} else if !simConfig.UseMMU && simConfig.UseCache {
// Wrap the RAM behind Cache
cacheMemory = cache.New(context, ram)
cpuMemory = cacheMemory
} else if simConfig.UseMMU && simConfig.UseCache {
// Wrap the RAM behind Cache and wrap Cache behind MMU
cacheMemory = cache.New(context, ram)
mmuMemory = mmu.New(context, cacheMemory)
cpuMemory = mmuMemory
}
cpu := cpu.New(context, cpuMemory)
if err != nil {
panic(err)
}
return &Sim{
config: simConfig,
cpu: cpu,
ram: ram,
cache: cacheMemory,
mmu: mmuMemory,
scheduler: simScheduler,
simQuitEvent: make(chan bool),
schedulerQuitEvent: schedulerQuitEvent,
}
}
func (s *Sim) Start() {
s.setStarted(true)
defer s.setStarted(false)
wg := &sync.WaitGroup{}
go s.cpu.Run(wg)
go s.scheduler.Run(wg)
// Wait for quit event
<-s.simQuitEvent
// Signal the scheduler to quit
s.schedulerQuitEvent <- false
wg.Wait()
// Do some cleanup
s.scheduler.Cleanup()
}
func (s *Sim) Stop() {
if s.started() {
s.simQuitEvent <- false
}
}
func (s *Sim) RegisterInstructionSet(instrSet []instr.InstrDesc) {
for _, instr := range instrSet {
s.cpu.RegisterInstr(instr)
}
}
func (s *Sim) Cpu() *cpu.Cpu {
return s.cpu
}
func (s *Sim) Ram() *ram.RAM {
return s.ram
}
func (s *Sim) UseMMU() bool {
return s.config.UseMMU
}
func (s *Sim) MMU() *mmu.MMU {
return s.mmu
}
func (s *Sim) UseCache() bool {
return s.config.UseCache
}
func (s *Sim) Cache() *cache.Cache {
return s.cache
}
func (s *Sim) setStarted(started bool) {
s.status.Lock()
defer s.status.Unlock()
s.status.Started = started
}
func (s *Sim) started() bool {
s.status.Lock()
defer s.status.Unlock()
return s.status.Started
}

11
pkg/simcontext/context.go Normal file
View File

@ -0,0 +1,11 @@
package simcontext
import (
"git.elyanpoujol.fr/elyan/central-arch/pkg/events"
"git.elyanpoujol.fr/elyan/central-arch/pkg/simstep"
)
type SimContext struct {
EventLogger events.EventLogger
Stepper simstep.SimStepper
}

44
pkg/simstate/state.go Normal file
View File

@ -0,0 +1,44 @@
package simstate
import (
"git.elyanpoujol.fr/elyan/central-arch/pkg/register"
)
type CpuRegisters struct {
Gprs [register.GPR_COUNT]uint32
Lr uint32
PcUser uint32
SpUser uint32
PcSvc uint32
SpSvc uint32
PcFault uint32
SpFault uint32
}
type CpuStatusRegisters struct {
Psr uint32
EsrSvc uint32
EsrFault uint32
}
type CpuState struct {
Registers CpuRegisters
StatusRegisters CpuStatusRegisters
}
type RamState struct {
Data []uint32
}
// TODO Implement it
type CacheState struct{}
// TODO Implement it
type MmuState struct{}
type SimState struct {
CpuState *CpuState
RamState *RamState
CacheState *CacheState
MmuState *MmuState
}

17
pkg/simstep/stepper.go Normal file
View File

@ -0,0 +1,17 @@
package simstep
import (
"errors"
"git.elyanpoujol.fr/elyan/central-arch/pkg/events"
)
var SimQuitRequest = errors.New("simulation quit requested")
type SimStepRequest interface {
events.SimEvent
}
type SimStepper interface {
RequestStep(req SimStepRequest) error
}

View File

@ -0,0 +1,6 @@
package subsystem
type Subsystem interface {
Read(register uint8, cmd uint8) (uint32, error)
Write(register uint8, cmd uint8, value uint32) error
}