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.memory
19 
20 import scala.util.{Failure, Success, Try}
21 
22 /**
23   * A generic memory type. A memory type can address bytes up to a maximum of 2^64^ bytes.
24   */
25 trait Memory {
26 
27   /**
28     * Returns the size of the memory.
29     * @return the size of the memory
30     */
31   def size: Long
32 
33   /**
34     * Read a single `Byte` from the memory at the given address.
35     * @param address the `address` to read from
36     * @return a `Success` with the Byte read or a `Failure`
37     */
38   def readByte(address: Long): Try[Byte]
39 
40   /**
41     * Write a single `Byte` to the memory at the given address.
42     * @param address the `address` to write to
43     * @param value the `value` to write
44     * @return a `Success` when the byte was written successfully or a `Failure` otherwise
45     */
46   def writeByte(address: Long, value: Byte): Try[Unit]
47 
48   /**
49     * Read a `Short` from the memory at `address ... address + 1`. The value of `address` will be the least significant
50     * `Byte`.
51     * @param address the `address` to read from
52     * @return a `Success` with the `Short` read or a `Failure`
53     */
54   final def readShort(address: Long): Try[Short] = {
55     val bytes = List.range(0, 2).map(offs => readByte(address + offs))
56     val failures = bytes.filter(x => x.isFailure)
57     if (failures.isEmpty) {
58       Success((readSumBytes(bytes) & 0xffffL).asInstanceOf[Short])
59     } else {
60       failures.head.asInstanceOf[Failure[Short]]
61     }
62   }
63 
64   /**
65     * Write a `Short` to `address ... address + 1`. The least significant `Byte` will be written to `address`.
66     * @param address the `address` to write to
67     * @param value the `value` to write
68     * @return a `Success` when the short was written successfully or a `Failure` otherwise
69     */
70   final def writeShort(address: Long, value: Short): Try[Unit] = {
71     writeDivided(address, value, 2)
72   }
73 
74   /**
75     * Read an `Int` from the memory at `address ... address + 3`. The value of `address` will be the least significant
76     * `Byte`.
77     * @param address the `address` to read from
78     * @return a `Success` with the `Int` read or a `Failure`
79     */
80   final def readInt(address: Long): Try[Int] = {
81     val bytes = List.range(0, 4).map(offs => readByte(address + offs))
82     val failures = bytes.filter(x => x.isFailure)
83     if (failures.isEmpty) {
84       Success((readSumBytes(bytes) & 0xffffffffL).asInstanceOf[Int])
85     } else {
86       failures.head.asInstanceOf[Failure[Int]]
87     }
88   }
89 
90   /**
91     * Write an `Int` at `address ... address + 3`. The least significant `Byte` will be written to `address`.
92     * @param address the `address` to write to
93     * @param value the `value` to write
94     * @return a `Success` when the int was written successfully or a `Failure` otherwise
95     */
96   final def writeInt(address: Long, value: Int): Try[Unit] = {
97     writeDivided(address, value, 4)
98   }
99 
100   /**
101     * Read a `Long` from the memory at `address ... address + 7`. The value of `address` will be the least significant
102     * `Byte`.
103     * @param address the `address` to read from
104     * @return a `Success` with the `Long` read or a `Failure`
105     */
106   final def readLong(address: Long): Try[Long] = {
107     val bytes = List.range(0, 8).map(offs => readByte(address + offs))
108     val failures = bytes.filter(x => x.isFailure)
109     if (failures.isEmpty) {
110       Success(readSumBytes(bytes) & 0xffffffffffffffffL)
111     } else {
112       failures.head.asInstanceOf[Failure[Long]]
113     }
114   }
115 
116   /**
117     * Write a `Long` at `address ... address + 7`. The least significant `Byte` will be written to `address`.
118     * @param address the `address` to write to
119     * @param value the `value` to write
120     * @return a `Success` when the long was written successfully or a `Failure` otherwise
121     */
122   final def writeLong(address: Long, value: Long): Try[Unit] = {
123     writeDivided(address, value, 8)
124   }
125 
126   /**
127     * Write the `value` into the memory starting at `address` divided to `numberBytes` bytes.
128     * @param address the start address of the write
129     * @param value the value to write
130     * @param numberBytes the number of bytes to write
131     * @return a `Success` if no error occurred during the write, `Failure` otherwiese
132     */
133   private def writeDivided(address: Long, value: Long, numberBytes: Int): Try[Unit] = {
134     val offsets = List.range(0, numberBytes)
135     val result = offsets.map(offset => writeByte(address + offset, (value >> (offset * 8) & 0xff).asInstanceOf[Byte]))
136     val failures = result.filter(x => x.isFailure)
137     if (failures.isEmpty) {
138       Success((): Unit)
139     } else {
140       failures.head
141     }
142   }
143 
144   /**
145     * Sums up the bytes according. The first byte in the list is the least significant byte.
146     * @param bytes the bytes to sum up
147     * @return the combined bytes
148     */
149   private def readSumBytes(bytes: List[Try[Byte]]): Long = {
150     bytes.collect { case Success(b) => b.asInstanceOf[Long] & 0xff }
151         .zipWithIndex
152         .map { case (l, i) => l << (i * 8) }
153         .sum
154   }
155 
156 }
Line Stmt Id Pos Tree Symbol Code
55 101 1981 - 1995 Apply scala.Long.+ address.+(offs)
55 98 1954 - 1955 Literal <nosymbol> 0
55 100 1953 - 1953 Select scala.math.Numeric.IntIsIntegral math.this.Numeric.IntIsIntegral
55 103 1943 - 1997 Apply scala.collection.immutable.List.map scala.collection.immutable.List.range[Int](0, 2)(math.this.Numeric.IntIsIntegral).map[scala.util.Try[Byte]](((offs: Int) => Memory.this.readByte(address.+(offs))))
55 99 1957 - 1958 Literal <nosymbol> 2
55 102 1972 - 1996 Apply info.osdevelopment.sysemu.memory.Memory.readByte Memory.this.readByte(address.+(offs))
56 104 2035 - 2046 Select scala.util.Try.isFailure x.isFailure
56 105 2017 - 2047 Apply scala.collection.immutable.List.filter bytes.filter(((x: scala.util.Try[Byte]) => x.isFailure))
57 106 2056 - 2072 Select scala.collection.immutable.List.isEmpty failures.isEmpty
58 110 2082 - 2142 Block scala.util.Success.apply scala.util.Success.apply[Short](Memory.this.readSumBytes(bytes).&(65535L).asInstanceOf[Short])
58 107 2113 - 2120 Literal <nosymbol> 65535L
58 109 2082 - 2142 Apply scala.util.Success.apply scala.util.Success.apply[Short](Memory.this.readSumBytes(bytes).&(65535L).asInstanceOf[Short])
58 108 2091 - 2141 TypeApply scala.Any.asInstanceOf Memory.this.readSumBytes(bytes).&(65535L).asInstanceOf[Short]
60 112 2162 - 2204 Block scala.Any.asInstanceOf failures.head.asInstanceOf[scala.util.Failure[Short]]
60 111 2162 - 2204 TypeApply scala.Any.asInstanceOf failures.head.asInstanceOf[scala.util.Failure[Short]]
71 113 2611 - 2616 Select scala.Short.toLong value.toLong
71 115 2589 - 2620 Apply info.osdevelopment.sysemu.memory.Memory.writeDivided Memory.this.writeDivided(address, value.toLong, 2)
71 114 2618 - 2619 Literal <nosymbol> 2
81 119 2984 - 2998 Apply scala.Long.+ address.+(offs)
81 116 2957 - 2958 Literal <nosymbol> 0
81 118 2956 - 2956 Select scala.math.Numeric.IntIsIntegral math.this.Numeric.IntIsIntegral
81 121 2946 - 3000 Apply scala.collection.immutable.List.map scala.collection.immutable.List.range[Int](0, 4)(math.this.Numeric.IntIsIntegral).map[scala.util.Try[Byte]](((offs: Int) => Memory.this.readByte(address.+(offs))))
81 120 2975 - 2999 Apply info.osdevelopment.sysemu.memory.Memory.readByte Memory.this.readByte(address.+(offs))
81 117 2960 - 2961 Literal <nosymbol> 4
82 122 3038 - 3049 Select scala.util.Try.isFailure x.isFailure
82 123 3020 - 3050 Apply scala.collection.immutable.List.filter bytes.filter(((x: scala.util.Try[Byte]) => x.isFailure))
83 124 3059 - 3075 Select scala.collection.immutable.List.isEmpty failures.isEmpty
84 128 3085 - 3147 Block scala.util.Success.apply scala.util.Success.apply[Int](Memory.this.readSumBytes(bytes).&(4294967295L).asInstanceOf[Int])
84 125 3116 - 3127 Literal <nosymbol> 4294967295L
84 127 3085 - 3147 Apply scala.util.Success.apply scala.util.Success.apply[Int](Memory.this.readSumBytes(bytes).&(4294967295L).asInstanceOf[Int])
84 126 3094 - 3146 TypeApply scala.Any.asInstanceOf Memory.this.readSumBytes(bytes).&(4294967295L).asInstanceOf[Int]
86 130 3167 - 3207 Block scala.Any.asInstanceOf failures.head.asInstanceOf[scala.util.Failure[Int]]
86 129 3167 - 3207 TypeApply scala.Any.asInstanceOf failures.head.asInstanceOf[scala.util.Failure[Int]]
97 131 3607 - 3612 Select scala.Int.toLong value.toLong
97 133 3585 - 3616 Apply info.osdevelopment.sysemu.memory.Memory.writeDivided Memory.this.writeDivided(address, value.toLong, 4)
97 132 3614 - 3615 Literal <nosymbol> 4
107 137 3983 - 3997 Apply scala.Long.+ address.+(offs)
107 134 3956 - 3957 Literal <nosymbol> 0
107 136 3955 - 3955 Select scala.math.Numeric.IntIsIntegral math.this.Numeric.IntIsIntegral
107 139 3945 - 3999 Apply scala.collection.immutable.List.map scala.collection.immutable.List.range[Int](0, 8)(math.this.Numeric.IntIsIntegral).map[scala.util.Try[Byte]](((offs: Int) => Memory.this.readByte(address.+(offs))))
107 138 3974 - 3998 Apply info.osdevelopment.sysemu.memory.Memory.readByte Memory.this.readByte(address.+(offs))
107 135 3959 - 3960 Literal <nosymbol> 8
108 140 4037 - 4048 Select scala.util.Try.isFailure x.isFailure
108 141 4019 - 4049 Apply scala.collection.immutable.List.filter bytes.filter(((x: scala.util.Try[Byte]) => x.isFailure))
109 142 4058 - 4074 Select scala.collection.immutable.List.isEmpty failures.isEmpty
110 145 4084 - 4134 Block scala.util.Success.apply scala.util.Success.apply[Long](Memory.this.readSumBytes(bytes).&(-1L))
110 144 4084 - 4134 Apply scala.util.Success.apply scala.util.Success.apply[Long](Memory.this.readSumBytes(bytes).&(-1L))
110 143 4092 - 4133 Apply scala.Long.& Memory.this.readSumBytes(bytes).&(-1L)
112 146 4154 - 4195 TypeApply scala.Any.asInstanceOf failures.head.asInstanceOf[scala.util.Failure[Long]]
112 147 4154 - 4195 Block scala.Any.asInstanceOf failures.head.asInstanceOf[scala.util.Failure[Long]]
123 148 4576 - 4607 Apply info.osdevelopment.sysemu.memory.Memory.writeDivided Memory.this.writeDivided(address, value, 8)
134 149 5067 - 5068 Literal <nosymbol> 0
134 151 5056 - 5082 ApplyToImplicitArgs scala.collection.IterableFactory.range scala.collection.immutable.List.range[Int](0, numberBytes)(math.this.Numeric.IntIsIntegral)
134 150 5066 - 5066 Select scala.math.Numeric.IntIsIntegral math.this.Numeric.IntIsIntegral
135 155 5151 - 5199 TypeApply scala.Any.asInstanceOf value.>>(offset.*(8)).&(255).asInstanceOf[Byte]
135 154 5175 - 5179 Literal <nosymbol> 255
135 157 5100 - 5201 Apply scala.collection.immutable.List.map offsets.map[scala.util.Try[Unit]](((offset: Int) => Memory.this.writeByte(address.+(offset), value.>>(offset.*(8)).&(255).asInstanceOf[Byte])))
135 156 5122 - 5200 Apply info.osdevelopment.sysemu.memory.Memory.writeByte Memory.this.writeByte(address.+(offset), value.>>(offset.*(8)).&(255).asInstanceOf[Byte])
135 153 5161 - 5171 Apply scala.Int.* offset.*(8)
135 152 5132 - 5148 Apply scala.Long.+ address.+(offset)
136 158 5240 - 5251 Select scala.util.Try.isFailure x.isFailure
136 159 5221 - 5252 Apply scala.collection.immutable.List.filter result.filter(((x: scala.util.Try[Unit]) => x.isFailure))
137 160 5261 - 5277 Select scala.collection.immutable.List.isEmpty failures.isEmpty
138 163 5287 - 5304 Block scala.util.Success.apply scala.util.Success.apply[Unit](((): Unit))
138 162 5287 - 5304 Apply scala.util.Success.apply scala.util.Success.apply[Unit](((): Unit))
138 161 5295 - 5297 Literal <nosymbol> ()
140 164 5324 - 5337 Select scala.collection.IterableOps.head failures.head
140 165 5324 - 5337 Block scala.collection.IterableOps.head failures.head
150 167 5606 - 5606 Apply info.osdevelopment.sysemu.memory.Memory.$anonfun.<init> new $anonfun()
150 166 5627 - 5654 Apply scala.Long.& b.asInstanceOf[Long].&(255)
152 169 5709 - 5721 Apply scala.Long.<< l.<<(i.*(8))
152 168 5715 - 5720 Apply scala.Int.* i.*(8)
153 171 5592 - 5736 ApplyToImplicitArgs scala.collection.IterableOnceOps.sum bytes.collect[Long](({ @SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[scala.util.Try[Byte],Long] with java.io.Serializable { def <init>(): <$anon: scala.util.Try[Byte] => Long> = { $anonfun.super.<init>(); () }; final override def applyOrElse[A1 <: scala.util.Try[Byte], B1 >: Long](x1: A1, default: A1 => B1): B1 = ((x1.asInstanceOf[scala.util.Try[Byte]]: scala.util.Try[Byte]): scala.util.Try[Byte] @unchecked) match { case (value: Byte)scala.util.Success[Byte]((b @ _)) => b.asInstanceOf[Long].&(255) case (defaultCase$ @ _) => default.apply(x1) }; final def isDefinedAt(x1: scala.util.Try[Byte]): Boolean = ((x1.asInstanceOf[scala.util.Try[Byte]]: scala.util.Try[Byte]): scala.util.Try[Byte] @unchecked) match { case (value: Byte)scala.util.Success[Byte]((b @ _)) => true case (defaultCase$ @ _) => false } }; new $anonfun() }: PartialFunction[scala.util.Try[Byte],Long])).zipWithIndex.map[Long](((x0$1: (Long, Int)) => x0$1 match { case (_1: Long, _2: Int)(Long, Int)((l @ _), (i @ _)) => l.<<(i.*(8)) })).sum[Long](math.this.Numeric.LongIsIntegral)
153 170 5733 - 5733 Select scala.math.Numeric.LongIsIntegral math.this.Numeric.LongIsIntegral