1 /*
2  * sys-emu - A system emulator for tutorials
3  * Copyright (C) 2018 - 2019 osdevelopment-info
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
18 package info.osdevelopment.sysemu.processor
19 
20 import info.osdevelopment.sysemu.memory.Memory
21 import scala.util.Try
22 
23 /**
24   * An abstract class defining a processor in a system.
25   * @param descriptor the descriptor of the processor.
26   */
27 abstract class Processor (val descriptor: ProcessorDescriptor) {
28 
29   val name: String = descriptor.name
30   val maxMemory: Long = descriptor.maxMemory
31   val romName: String = descriptor.romName
32 
33   /**
34     * The memory map of the processor.
35     */
36   val memoryMap: collection.mutable.Map[Long, Memory] = collection.mutable.Map[Long, Memory]()
37 
38   /**
39     * Adds a memory area to this processor. The memory has a base address (the lowest address handled by this
40     * processor).
41     * @param baseAddress the base address of the memory to add
42     * @param memory the memory to add
43     */
44   def addMemory(baseAddress: Long, memory: Memory): Unit = {
45     memoryMap.foreach(address => {
46       val startAddress = address._1
47       val endAddress = startAddress + address._2.size
48       if (baseAddress >= startAddress & baseAddress < endAddress)
49         throw new IllegalMemoryLayoutException("Memory overlaps")
50       if (baseAddress + memory.size >= startAddress & baseAddress + memory.size < endAddress)
51         throw new IllegalMemoryLayoutException("Memory overlaps")
52       if (baseAddress <= startAddress & baseAddress + memory.size >= endAddress)
53         throw new IllegalMemoryLayoutException("Memory overlaps")
54     })
55     if (baseAddress + memory.size > maxMemory) throw new IllegalMemoryLayoutException("Memory exceeds max memory")
56     memoryMap += baseAddress -> memory
57   }
58 
59   /**
60     * All registers of all cores when the cores are stopped.
61     *
62     * The result is Success if the cores can return the registers. When Failure is returned then the cores
63     * cannot return the registers at the moment, e.g. because any is running at the moment.
64     *
65     * The key of the map is the register name.
66     *
67     * @return A Try containing a Map with the core as key and a Map with the register name as key and the register as
68     *         value.
69     */
70   def registers: Try[Map[Int, Map[String, Register]]]
71 
72   /**
73     * All registers of a core when the core is stopped.
74     *
75     * The result is Success if the core can return the registers. When Failure is returned then the core
76     * cannot return the registers at the moment, e.g. because it is running at the moment.
77     *
78     * The key of the map is the register name.
79     *
80     * @param core the core for which the registers should be queried
81     * @return A Try containing a Map with the register name as key and the register as value.
82     */
83   def registers(core: Int): Try[Map[String, Register]]
84 
85   /**
86     * Return the register with the given name of the given core, e.g. "AX" or "D1".
87     *
88     * @param core the core for which the register should be returned
89     * @param name the name of the register to return
90     * @return the register named by name. Failure if the register does not exist or cannot be returned.
91     */
92   def register(core: Int, name: String): Try[Register]
93 
94   /**
95     * Sets the register of the processor to the given content.
96     *
97     * The returned register (in case of Success(_)) contains the new register content. Failure is returned in case that
98     *  - the processor is running and therefore the register cannot be set
99     *  - the register is unknown to the processor
100     *  - the value of the register is invalid
101     *
102     * @param register the register to set
103     * @return Success with the new register value or Failure if the register cannot be set.
104     */
105   def register(register: Register): Try[Register]
106 
107   /**
108     * Calculates the start address for a ROM/BIOS based on the size. The start address may be constant or dynamic
109     * depending on the size (e.g. for x86). The start address is not necessarily the start address for the processor.
110     * The start address is None if the ROM/BIOS is too large for the processor.
111     * @return the start address for the ROM/BIOS depending on the architecture
112     */
113   def calculateRomStart(romSize: Long): Option[Long]
114 
115   /**
116     * Resets the processor and starts it new.
117     */
118   def reset(): Unit
119 
120   /**
121     * Do a single step of the processor (normally execute the next instruction).
122     */
123   def step(): Unit
124 
125 }
Line Stmt Id Pos Tree Symbol Code
29 286 1093 - 1108 Select info.osdevelopment.sysemu.processor.ProcessorDescriptor.name Processor.this.descriptor.name
30 287 1133 - 1153 Select info.osdevelopment.sysemu.processor.ProcessorDescriptor.maxMemory Processor.this.descriptor.maxMemory
31 288 1178 - 1196 Select info.osdevelopment.sysemu.processor.ProcessorDescriptor.romName Processor.this.descriptor.romName
36 289 1306 - 1344 Apply scala.collection.MapFactory.Delegate.apply scala.collection.mutable.Map.apply[Long, info.osdevelopment.sysemu.memory.Memory]()
45 312 1653 - 2219 Apply scala.collection.IterableOnceOps.foreach Processor.this.memoryMap.foreach[Unit](((address: (Long, info.osdevelopment.sysemu.memory.Memory)) => { val startAddress: Long = address._1; val endAddress: Long = startAddress.+(address._2.size); if (baseAddress.>=(startAddress).&(baseAddress.<(endAddress))) throw new IllegalMemoryLayoutException("Memory overlaps") else (); if (baseAddress.+(memory.size).>=(startAddress).&(baseAddress.+(memory.size).<(endAddress))) throw new IllegalMemoryLayoutException("Memory overlaps") else (); if (baseAddress.<=(startAddress).&(baseAddress.+(memory.size).>=(endAddress))) throw new IllegalMemoryLayoutException("Memory overlaps") else () }))
46 290 1709 - 1719 Select scala.Tuple2._1 address._1
47 292 1743 - 1773 Apply scala.Long.+ startAddress.+(address._2.size)
47 291 1758 - 1773 Select info.osdevelopment.sysemu.memory.Memory.size address._2.size
48 298 1780 - 1780 Block <nosymbol> ()
48 294 1784 - 1838 Apply scala.Boolean.& baseAddress.>=(startAddress).&(baseAddress.<(endAddress))
48 297 1780 - 1780 Literal <nosymbol> ()
48 293 1814 - 1838 Apply scala.Long.< baseAddress.<(endAddress)
49 295 1848 - 1905 Throw <nosymbol> throw new IllegalMemoryLayoutException("Memory overlaps")
49 296 1848 - 1905 Block <nosymbol> throw new IllegalMemoryLayoutException("Memory overlaps")
50 304 1912 - 1912 Literal <nosymbol> ()
50 301 1916 - 1998 Apply scala.Boolean.& baseAddress.+(memory.size).>=(startAddress).&(baseAddress.+(memory.size).<(endAddress))
50 300 1960 - 1998 Apply scala.Long.< baseAddress.+(memory.size).<(endAddress)
50 299 1930 - 1941 Select info.osdevelopment.sysemu.memory.Memory.size memory.size
50 305 1912 - 1912 Block <nosymbol> ()
51 303 2008 - 2065 Block <nosymbol> throw new IllegalMemoryLayoutException("Memory overlaps")
51 302 2008 - 2065 Throw <nosymbol> throw new IllegalMemoryLayoutException("Memory overlaps")
52 307 2076 - 2145 Apply scala.Boolean.& baseAddress.<=(startAddress).&(baseAddress.+(memory.size).>=(endAddress))
52 310 2072 - 2072 Literal <nosymbol> ()
52 306 2106 - 2145 Apply scala.Long.>= baseAddress.+(memory.size).>=(endAddress)
52 311 2072 - 2072 Block <nosymbol> ()
53 309 2155 - 2212 Block <nosymbol> throw new IllegalMemoryLayoutException("Memory overlaps")
53 308 2155 - 2212 Throw <nosymbol> throw new IllegalMemoryLayoutException("Memory overlaps")
55 313 2242 - 2253 Select info.osdevelopment.sysemu.memory.Memory.size memory.size
55 316 2267 - 2334 Throw <nosymbol> throw new IllegalMemoryLayoutException("Memory exceeds max memory")
55 319 2224 - 2224 Block <nosymbol> ()
55 318 2224 - 2224 Literal <nosymbol> ()
55 315 2228 - 2265 Apply scala.Long.> baseAddress.+(memory.size).>(Processor.this.maxMemory)
55 317 2267 - 2334 Block <nosymbol> throw new IllegalMemoryLayoutException("Memory exceeds max memory")
55 314 2256 - 2265 Select info.osdevelopment.sysemu.processor.Processor.maxMemory Processor.this.maxMemory
56 322 2349 - 2349 Literal <nosymbol> ()
56 321 2339 - 2373 Apply scala.collection.mutable.Growable.+= Processor.this.memoryMap.+=(scala.Predef.ArrowAssoc[Long](baseAddress).->[info.osdevelopment.sysemu.memory.Memory](memory))
56 320 2352 - 2373 Apply scala.Predef.ArrowAssoc.-> scala.Predef.ArrowAssoc[Long](baseAddress).->[info.osdevelopment.sysemu.memory.Memory](memory)