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 info.osdevelopment.sysemu.support.Utilities._
21 import java.nio.ByteBuffer
22 import java.nio.channels.SeekableByteChannel
23 import scala.util.Try
24 
25 /**
26   * A read-only memory backed by a `SeekableByteChannel`, e.g. a file. This
27   * implementation reads part of the file into a cache and tries to serve the data from this cache.
28   * @param data the data of the read-only memory
29   */
30 class ChannelReadOnlyMemory(val data: SeekableByteChannel) extends ReadOnlyMemory {
31 
32   /** The number of the block that is cached. */
33   private var cachedBlock = -1L
34   /** The cache of the read-only memory. */
35   private val romCache = ByteBuffer.allocate(256.Ki.asInstanceOf[Int])
36   /** The number of bytes read from the channel during the last caching operation. */
37   private var cachedBytes = -1
38 
39   /**
40     * Returns the size of the memory.
41     * @return the size of the memory
42     */
43   override def size: Long = data.size
44 
45   /**
46     * The read method which caches a block of data and returns the value to be read from the cache.
47     * @param address the address to read
48     * @return a `Success` with the byte read at the given address or a `Failure`
49     */
50   override protected def doRead(address: Long): Try[Byte] = {
51     val block = address / 256.Ki
52     Try {
53       // In the cache is the wrong block
54       if (block != cachedBlock) {
55         data.position(block * 256.Ki)
56         romCache.clear
57         cachedBytes = data.read(romCache)
58         cachedBlock = block
59       }
60       val indexInCache = (address % 256.Ki).asInstanceOf[Int]
61       if (indexInCache > cachedBytes) throw new IllegalAddressException("Address outside memory")
62       romCache.get(indexInCache)
63     }
64   }
65 
66 }
Line Stmt Id Pos Tree Symbol Code
33 13 1357 - 1360 Literal <nosymbol> -1L
35 14 1450 - 1453 Literal <nosymbol> 256L
35 16 1430 - 1475 Apply java.nio.ByteBuffer.allocate java.nio.ByteBuffer.allocate(info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki.asInstanceOf[Int])
35 15 1450 - 1474 TypeApply scala.Any.asInstanceOf info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki.asInstanceOf[Int]
37 17 1590 - 1592 Literal <nosymbol> -1
43 18 1710 - 1719 Apply java.nio.channels.SeekableByteChannel.size ChannelReadOnlyMemory.this.data.size()
51 20 2044 - 2050 Select info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong.Ki info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki
51 19 2044 - 2047 Literal <nosymbol> 256L
51 21 2034 - 2050 Apply scala.Long./ address./(info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki)
52 46 2055 - 2473 Apply scala.util.Try.apply scala.util.Try.apply[Byte]({ if (block.!=(ChannelReadOnlyMemory.this.cachedBlock)) { ChannelReadOnlyMemory.this.data.position(block.*(info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki)); ChannelReadOnlyMemory.this.romCache.clear(); ChannelReadOnlyMemory.this.cachedBytes_=(ChannelReadOnlyMemory.this.data.read(ChannelReadOnlyMemory.this.romCache)); ChannelReadOnlyMemory.this.cachedBlock_=(block) } else (); val indexInCache: Int = address.%(info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki).asInstanceOf[Int]; if (indexInCache.>(ChannelReadOnlyMemory.this.cachedBytes)) throw new IllegalAddressException("Address outside memory") else (); ChannelReadOnlyMemory.this.romCache.get(indexInCache) })
54 23 2112 - 2132 Apply scala.Long.!= block.!=(ChannelReadOnlyMemory.this.cachedBlock)
54 35 2108 - 2108 Block <nosymbol> ()
54 22 2121 - 2132 Select info.osdevelopment.sysemu.memory.ChannelReadOnlyMemory.cachedBlock ChannelReadOnlyMemory.this.cachedBlock
54 34 2108 - 2108 Literal <nosymbol> ()
54 33 2134 - 2274 Block <nosymbol> { ChannelReadOnlyMemory.this.data.position(block.*(info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki)); ChannelReadOnlyMemory.this.romCache.clear(); ChannelReadOnlyMemory.this.cachedBytes_=(ChannelReadOnlyMemory.this.data.read(ChannelReadOnlyMemory.this.romCache)); ChannelReadOnlyMemory.this.cachedBlock_=(block) }
55 26 2158 - 2172 Apply scala.Long.* block.*(info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki)
55 25 2166 - 2172 Select info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong.Ki info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki
55 27 2144 - 2173 Apply java.nio.channels.SeekableByteChannel.position ChannelReadOnlyMemory.this.data.position(block.*(info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki))
55 24 2166 - 2169 Literal <nosymbol> 256L
56 28 2182 - 2196 Apply java.nio.Buffer.clear ChannelReadOnlyMemory.this.romCache.clear()
57 29 2229 - 2237 Select info.osdevelopment.sysemu.memory.ChannelReadOnlyMemory.romCache ChannelReadOnlyMemory.this.romCache
57 31 2205 - 2238 Apply info.osdevelopment.sysemu.memory.ChannelReadOnlyMemory.cachedBytes_= ChannelReadOnlyMemory.this.cachedBytes_=(ChannelReadOnlyMemory.this.data.read(ChannelReadOnlyMemory.this.romCache))
57 30 2219 - 2238 Apply java.nio.channels.SeekableByteChannel.read ChannelReadOnlyMemory.this.data.read(ChannelReadOnlyMemory.this.romCache)
58 32 2247 - 2266 Apply info.osdevelopment.sysemu.memory.ChannelReadOnlyMemory.cachedBlock_= ChannelReadOnlyMemory.this.cachedBlock_=(block)
60 38 2301 - 2336 TypeApply scala.Any.asInstanceOf address.%(info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki).asInstanceOf[Int]
60 37 2311 - 2317 Select info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong.Ki info.osdevelopment.sysemu.support.Utilities.BinaryUnitLong(256L).Ki
60 36 2311 - 2314 Literal <nosymbol> 256L
61 41 2375 - 2434 Throw <nosymbol> throw new IllegalAddressException("Address outside memory")
61 44 2343 - 2343 Block <nosymbol> ()
61 40 2347 - 2373 Apply scala.Int.> indexInCache.>(ChannelReadOnlyMemory.this.cachedBytes)
61 43 2343 - 2343 Literal <nosymbol> ()
61 39 2362 - 2373 Select info.osdevelopment.sysemu.memory.ChannelReadOnlyMemory.cachedBytes ChannelReadOnlyMemory.this.cachedBytes
61 42 2375 - 2434 Block <nosymbol> throw new IllegalAddressException("Address outside memory")
62 45 2441 - 2467 Apply java.nio.ByteBuffer.get ChannelReadOnlyMemory.this.romCache.get(indexInCache)