diff options
author | Araq <rumpf_a@web.de> | 2013-03-24 13:12:16 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2013-03-24 13:12:16 +0100 |
commit | 0eae08af7e65c8863e22236ddbf269516808767e (patch) | |
tree | 65acc85807bd4ddc1d7bdba5eff9c07f483ccb2a | |
parent | ba80bd807ca0f8562974aa4deae2b956cf6bf6d2 (diff) | |
parent | 52679849857b9a289ac5c75c420e6bce8680b3c7 (diff) | |
download | Nim-0eae08af7e65c8863e22236ddbf269516808767e.tar.gz |
Merge branch 'master' of github.com:Araq/Nimrod
-rw-r--r-- | lib/pure/asyncio.nim | 40 | ||||
-rw-r--r-- | lib/pure/sockets.nim | 90 | ||||
-rw-r--r-- | lib/pure/xmltree.nim | 3 | ||||
-rw-r--r-- | tests/manyloc/gbemulator/cpu.nim | 393 | ||||
-rw-r--r-- | tests/manyloc/gbemulator/cpu.nimrod.cfg | 2 | ||||
-rw-r--r-- | tests/manyloc/gbemulator/gpu.nim | 110 | ||||
-rw-r--r-- | tests/manyloc/gbemulator/mem.nim | 173 | ||||
-rw-r--r-- | tests/manyloc/gbemulator/readme.markdown | 12 | ||||
-rw-r--r-- | tests/run/tasynciossl.nim | 2 |
9 files changed, 130 insertions, 695 deletions
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim index be375a1a1..c5c1f5696 100644 --- a/lib/pure/asyncio.nim +++ b/lib/pure/asyncio.nim @@ -8,7 +8,8 @@ import sockets, os -## This module implements an asynchronous event loop for sockets. +## This module implements an asynchronous event loop together with asynchronous sockets +## which use this event loop. ## It is akin to Python's asyncore module. Many modules that use sockets ## have an implementation for this module, those modules should all have a ## ``register`` function which you should use to add the desired objects to a @@ -435,7 +436,8 @@ proc delHandleWrite*(s: PAsyncSocket) = ## Removes the ``handleWrite`` event handler on ``s``. s.handleWrite = nil -proc recvLine*(s: PAsyncSocket, line: var TaintedString): bool = +{.push warning[deprecated]: off.} +proc recvLine*(s: PAsyncSocket, line: var TaintedString): bool {.deprecated.} = ## Behaves similar to ``sockets.recvLine``, however it handles non-blocking ## sockets properly. This function guarantees that ``line`` is a full line, ## if this function can only retrieve some data; it will save this data and @@ -443,6 +445,9 @@ proc recvLine*(s: PAsyncSocket, line: var TaintedString): bool = ## ## Unlike ``sockets.recvLine`` this function will raise an EOS or ESSL ## exception if an error occurs. + ## + ## **Deprecated since version 0.9.2**: This function has been deprecated in + ## favour of readLine. setLen(line.string, 0) var dataReceived = "".TaintedString var ret = s.socket.recvLineAsync(dataReceived) @@ -463,6 +468,37 @@ proc recvLine*(s: PAsyncSocket, line: var TaintedString): bool = of RecvFail: s.SocketError(async = true) result = false +{.pop.} + +proc readLine*(s: PAsyncSocket, line: var TaintedString): bool = + ## Behaves similar to ``sockets.readLine``, however it handles non-blocking + ## sockets properly. This function guarantees that ``line`` is a full line, + ## if this function can only retrieve some data; it will save this data and + ## add it to the result when a full line is retrieved, when this happens + ## False will be returned. True will only be returned if a full line has been + ## retrieved or the socket has been disconnected in which case ``line`` will + ## be set to "". + ## + ## This function will raise an EOS exception when a socket error occurs. + setLen(line.string, 0) + var dataReceived = "".TaintedString + var ret = s.socket.readLineAsync(dataReceived) + case ret + of ReadFullLine: + if s.lineBuffer.len > 0: + string(line).add(s.lineBuffer.string) + setLen(s.lineBuffer.string, 0) + string(line).add(dataReceived.string) + if string(line) == "": + line = "\c\L".TaintedString + result = true + of ReadPartialLine: + string(s.lineBuffer).add(dataReceived.string) + result = false + of ReadNone: + result = false + of ReadDisconnected: + result = true proc send*(sock: PAsyncSocket, data: string) = ## Sends ``data`` to socket ``sock``. This is basically a nicer implementation diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index e70fbd09a..2d602c86e 100644 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -121,6 +121,9 @@ type TRecvLineResult* = enum ## result for recvLineAsync RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail + TReadLineResult* = enum ## result for readLineAsync + ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone + ETimeout* = object of ESynch proc newTSocket(fd: int32, isBuff: bool): TSocket = @@ -1180,7 +1183,7 @@ proc peekChar(socket: TSocket, c: var char): int {.tags: [FReadIO].} = result = recv(socket.fd, addr(c), 1, MSG_PEEK) proc recvLine*(socket: TSocket, line: var TaintedString, timeout = -1): bool {. - tags: [FReadIO, FTime].} = + tags: [FReadIO, FTime], deprecated.} = ## Receive a line of data from ``socket``. ## ## If a full line is received ``\r\L`` is not @@ -1196,6 +1199,10 @@ proc recvLine*(socket: TSocket, line: var TaintedString, timeout = -1): bool {. ## ## A timeout can be specified in miliseconds, if data is not received within ## the specified time an ETimeout exception will be raised. + ## + ## **Deprecated since version 0.9.2**: This function has been deprecated in + ## favour of readLine. + template addNLIfEmpty(): stmt = if line.len == 0: line.add("\c\L") @@ -1222,8 +1229,49 @@ proc recvLine*(socket: TSocket, line: var TaintedString, timeout = -1): bool {. return true add(line.string, c) +proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {. + tags: [FReadIO, FTime].} = + ## Reads a line of data from ``socket``. + ## + ## If a full line is read ``\r\L`` is not + ## added to ``line``, however if solely ``\r\L`` is read then ``line`` + ## will be set to it. + ## + ## If the socket is disconnected, ``line`` will be set to ``""``. + ## + ## An EOS exception will be raised in the case of a socket error. + ## + ## A timeout can be specified in miliseconds, if data is not received within + ## the specified time an ETimeout exception will be raised. + + template addNLIfEmpty(): stmt = + if line.len == 0: + line.add("\c\L") + + var waited = 0.0 + + setLen(line.string, 0) + while true: + var c: char + discard waitFor(socket, waited, timeout, 1, "readLine") + var n = recv(socket, addr(c), 1) + if n < 0: OSError() + elif n == 0: return + if c == '\r': + discard waitFor(socket, waited, timeout, 1, "readLine") + n = peekChar(socket, c) + if n > 0 and c == '\L': + discard recv(socket, addr(c), 1) + elif n <= 0: OSError() + addNlIfEmpty() + return + elif c == '\L': + addNlIfEmpty() + return + add(line.string, c) + proc recvLineAsync*(socket: TSocket, - line: var TaintedString): TRecvLineResult {.tags: [FReadIO].} = + line: var TaintedString): TRecvLineResult {.tags: [FReadIO], deprecated.} = ## Similar to ``recvLine`` but designed for non-blocking sockets. ## ## The values of the returned enum should be pretty self explanatory: @@ -1232,6 +1280,10 @@ proc recvLineAsync*(socket: TSocket, ## * If some data has been retrieved; ``RecvPartialLine`` is returned. ## * If the socket has been disconnected; ``RecvDisconnected`` is returned. ## * If call to ``recv`` failed; ``RecvFail`` is returned. + ## + ## **Deprecated since version 0.9.2**: This function has been deprecated in + ## favour of readLineAsync. + setLen(line.string, 0) while true: var c: char @@ -1250,6 +1302,40 @@ proc recvLineAsync*(socket: TSocket, elif c == '\L': return RecvFullLine add(line.string, c) +proc readLineAsync*(socket: TSocket, + line: var TaintedString): TReadLineResult {.tags: [FReadIO].} = + ## Similar to ``recvLine`` but designed for non-blocking sockets. + ## + ## The values of the returned enum should be pretty self explanatory: + ## + ## * If a full line has been retrieved; ``ReadFullLine`` is returned. + ## * If some data has been retrieved; ``ReadPartialLine`` is returned. + ## * If the socket has been disconnected; ``ReadDisconnected`` is returned. + ## * If no data could be retrieved; ``ReadNone`` is returned. + ## * If call to ``recv`` failed; **an EOS exception is raised.** + setLen(line.string, 0) + + template errorOrNone = + socket.SocketError(async = true) + return ReadNone + + while true: + var c: char + var n = recv(socket, addr(c), 1) + if n < 0: + if line.len == 0: errorOrNone else: return ReadPartialLine + elif n == 0: + return (if line.len == 0: ReadDisconnected else: ReadPartialLine) + if c == '\r': + n = peekChar(socket, c) + if n > 0 and c == '\L': + discard recv(socket, addr(c), 1) + elif n <= 0: + if line.len == 0: errorOrNone else: return ReadPartialLine + return ReadFullLine + elif c == '\L': return ReadFullLine + add(line.string, c) + proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} = ## receives all the available data from the socket. ## Socket errors will result in an ``EOS`` error. diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 1a1467e8f..8cf484bfc 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -109,6 +109,7 @@ iterator items*(n: PXmlNode): PXmlNode {.inline.} = proc attrs*(n: PXmlNode): PXmlAttributes {.inline.} = ## gets the attributes belonging to `n`. + ## Returns `nil` if attributes have not been initialised for this node. assert n.k == xnElement result = n.fAttr @@ -282,5 +283,7 @@ proc child*(n: PXmlNode, name: string): PXmlNode = proc attr*(n: PXmlNode, name: string): string = ## Finds the first attribute of `n` with a name of `name`. + ## Returns "" on failure. assert n.kind == xnElement + if n.attrs == nil: return "" return n.attrs[name] diff --git a/tests/manyloc/gbemulator/cpu.nim b/tests/manyloc/gbemulator/cpu.nim deleted file mode 100644 index a8346b9ae..000000000 --- a/tests/manyloc/gbemulator/cpu.nim +++ /dev/null @@ -1,393 +0,0 @@ -# Part of the Nimrod Gameboy emulator. -# Copyright (C) Dominik Picheta. -import mem, gpu -import strutils -type - # m (machine cycles), t (time cycles). - # Ref: http://www.zilog.com/docs/z80/um0080.pdf - TClock = tuple[m, t: int] - - PRegister = ref object - pc, sp: int32 # 16-bit - a, b, c, d, e, H, L, f: int32 # 8-bit - clock: TClock - - PCPU = ref object - clock: TClock - r: PRegister - mem: PMem - - TFlagState = enum - FUnchanged, FSet, FUnset - -const - BitZ = 1 shl 7 - BitN = 1 shl 6 - BitH = 1 shl 5 - BitC = 1 shl 4 - -## Flags -## ----- -## 0x80 (1 shl 7) - (Zero|Z) Last result was zero. -## 0x40 (1 shl 6) - (Operation|N) Set if last operation was a subtraction -## 0x20 (1 shl 5) - (Half carry|H) -## 0x10 (1 shl 4) - (Carry|C) -## 0x08 (1 shl 3) - (Sign flag|S) NOT USED IN GB's Z80 -## 0x04 (1 shl 2) - (Parity/Overflow Flag|P/V) NOT USED IN GB's Z80 - -proc newCPU(mem: PMem): PCPU = - new(result) - new(result.r) - result.mem = mem - -# Split a 16-bit into 8-bit: let (a, b) = (x shr 8 and 0xff, x and 0xff) - -template changeFlag(f: var int32, state: TFlagState, bit: int32) = - case state - of FSet: - f = f or bit - of FUnset: - f = f and (not bit) - else: assert false - -template changeFlags(cpu: PCPU, Z = FUnchanged, N = FUnchanged, - H = FUnchanged, C = FUnchanged) = - if Z != FUnchanged: changeFlag(cpu.r.f, Z, BitZ) - if N != FUnchanged: changeFlag(cpu.r.f, N, BitN) - if H != FUnchanged: changeFlag(cpu.r.f, H, BitH) - if C != FUnchanged: changeFlag(cpu.r.f, C, BitC) - -template isFSet(cpu: PCPU, bit: int32): bool = (cpu.r.f and bit) != 0 - -proc `>>`(b: bool): TFlagState = - if b: return FSet - else: return FUnset - -proc `/<</`(v: int32, interval: int): int32 = - ## Circular shift 8-bit value left ``interval`` times. - let leftMost = v shr (8-interval) - result = ((v shl interval) or leftMost).int32 - result = result and 0xFF - -template LDrn(cpu: PCPU, register: expr) {.immediate.} = - cpu.r.register = cpu.mem.readByte(cpu.r.pc) - inc(cpu.r.pc) - cpu.r.clock.m = 2 - -template PUSHqq(cpu: PCPU, r1, r2: expr) {.immediate.} = - cpu.r.sp.dec - cpu.mem.writeByte(cpu.r.sp, cpu.r.r1) - cpu.r.sp.dec - cpu.mem.writeByte(cpu.r.sp, cpu.r.r2) - cpu.r.clock.m = 3 - -template POPqq(cpu: PCPU, r1, r2: expr) {.immediate.} = - ## r1 = High, r2 = Low - cpu.r.r2 = cpu.mem.readByte(cpu.r.sp) - cpu.r.sp.inc - cpu.r.r1 = cpu.mem.readByte(cpu.r.sp) - cpu.r.sp.inc - cpu.r.clock.m = 3 - -template RLr(cpu: PCPU, register: expr) {.immediate.} = - let bit7 = cpu.r.register shl 7 - let prevCarry = cpu.isFSet(BitC) - cpu.r.register = cpu.r.register /<</ 1 - if prevCarry: cpu.r.register = cpu.r.register or 1 # Set Bit 0 - else: cpu.r.register = cpu.r.register and (not 1) # Unset bit 0 - cpu.changeFlags(Z = >>(cpu.r.register == 0), H = FUnset, N = FUnset, - C = >>(bit7 == 1)) - cpu.r.clock.m = 2 - -template INCrr(cpu: PCPU, r1, r2: expr, flags = false) {.immediate.} = - let x = ((cpu.r.r1 shl 8) or cpu.r.r2) + 1 - let (hi, low) = (x shr 8 and 0xFF, x and 0xFF) - cpu.r.r2 = low; cpu.r.r1 = hi - if flags: - cpu.changeFlags(Z = >>(x == 0), H = >>((x and 0xF) == 0), N = FUnset) - cpu.r.clock.m = 3 - -template DECr(cpu: PCPU, register: expr) {.immediate.} = - cpu.r.register = (cpu.r.register - 1) and 0xFF - cpu.changeFlags(Z = >>(cpu.r.register == 0), - H = >>((cpu.r.register and 0xF) == 0xF), - N = FSet) - - cpu.r.clock.m = 1 - -proc LDSimple(cpu: PCPU, opcode: int32) = - ## All (simple) variants of the LD opcodes end up here. - ## Essentially what we want is a register to be copied to another register. - - case opcode - of 0x40 .. 0x45: - # LD B, B .. LD B, L - # TODO JUST USE A MACRO - assert false - - else: assert false - -proc exec(cpu: PCPU) = - ## Executes the next instruction - let opcode = cpu.mem.readByte(cpu.r.pc) - #echo("OPCODE: 0x", toHex(opcode, 2)) - cpu.r.pc.inc() - # PROBLEM: 0x7B is part of some range later but the compiler does not care! - case opcode - of 0x06: - # LD B, n - # Load 8-bit immediate into B - LDrn(cpu, b) - of 0x0E: - # LD C, n - # Load 8-bit immediate into C. - LDrn(cpu, c) - of 0x1E: - # LD E, n - LDrn(cpu, e) - of 0x2E: - # LD L, n - LDrn(cpu, L) - of 0x3E: - # LD A, n - # Load 8-bit immediate into A. - LDrn(cpu, a) - - of 0x0C: - # INC c - # Increment C - cpu.r.c = (cpu.r.c + 1) and 0xFF - cpu.r.clock.m = 1 - cpu.changeFlags(Z = >>(cpu.r.c == 0), H = >>((cpu.r.c and 0xF) == 0), - N = FUnset) - - of 0x03: - # INC BC - INCrr(cpu, b, c, true) - of 0x13: - # INC DE - INCrr(cpu, d, e, true) - of 0x23: - # INC HL - # Increment 16-bit HL - INCrr(cpu, H, L, true) - - of 0x05: - # DEC B - # Decrement B - DECr(cpu, b) - of 0x0D: - # DEC C - DECr(cpu, c) - of 0x1D: - # DEC E - DECr(cpu, e) - of 0x2D: - # DEC L - DECr(cpu, L) - of 0x3D: - # DEC A - DECr(cpu, a) - - of 0x11: - # LD DE, nn - # Load 16-bit immediate into DE - cpu.r.e = cpu.mem.readByte(cpu.r.pc) - cpu.r.d = cpu.mem.readByte(cpu.r.pc+1) - cpu.r.pc.inc(2) - cpu.r.clock.m = 3 - - of 0x17: - # RL A - # Rotate A left. - RLr(cpu, a) - - of 0x1A: - # LD A, (DE) - # Load A from address pointed to by DE - cpu.r.a = cpu.mem.readByte((cpu.r.d shl 8) or cpu.r.e) - cpu.r.clock.m = 2 - - of 0x20, 0x28: - # (0x20) JR NZ, n; Relative jump by signed immediate if last result was not zero - # (0x28) JR Z, n; Same as above, but when last result *was* zero. - var x = cpu.mem.readByte(cpu.r.pc) - if x > 127: x = -(((not x) + 1) and 255) - cpu.r.pc.inc - cpu.r.clock.m = 2 - if (opcode == 0x20 and (not isFSet(cpu, BitZ))) or - (opcode == 0x28 and isFSet(cpu, BitZ)): - cpu.r.pc.inc(x); cpu.r.clock.m.inc - of 0x18: - # JR n - # Relative jump by signed immediate - var x = cpu.mem.readByte(cpu.r.pc) - if x > 127: x = -(((not x) + 1) and 255) - cpu.r.pc.inc - cpu.r.pc.inc(x) - cpu.r.clock.m = 3 - - of 0x21: - # LD HL, nn - # Load 16-bit immediate into (registers) H and L - cpu.r.L = cpu.mem.readByte(cpu.r.pc) - cpu.r.H = cpu.mem.readByte(cpu.r.pc+1) - cpu.r.pc.inc(2) - cpu.r.clock.m = 3 - of 0x22: - # LDI (HL), A - # Save A to address pointed by HL and increment HL. - cpu.mem.writeByte((cpu.r.h shl 8) or cpu.r.l, cpu.r.a) - INCrr(cpu, H, L) - # TODO: Should flags be changed? (Z80 ref says they should.) - # cpu.changeFlags(H = FUnset, N = FUnset) - cpu.r.clock.m = 2 - - of 0x31: - # LD SP, nn - # Load 16-bit immediate into (register) SP - cpu.r.sp = cpu.mem.readWord(cpu.r.pc) - cpu.r.pc.inc(2) - cpu.r.clock.m = 3 - of 0x32: - # LDD (HL), A - # Save A to address pointed by HL, and decrement HL - cpu.mem.writeByte((cpu.r.h shl 8) or cpu.r.l, cpu.r.a) - let x = ((cpu.r.h shl 8) or cpu.r.l) - 1 - let (hi, low) = (x shr 8 and 0xFF, x and 0xFF) - cpu.r.L = low; cpu.r.H = hi - # TODO: Should flags be changed? (Z80 ref says they should.) - cpu.r.clock.m = 2 - - - of 0x7B: - # LD A, E; Copy E into A - cpu.r.a = cpu.r.e - cpu.r.clock.m = 1 - - of 0x77: - # LD (HL), A - # Copy A to address pointed by HL - let HL = ((cpu.r.h shl 8) or cpu.r.L) - cpu.mem.writeByte(HL, cpu.r.a) - cpu.r.clock.m = 2 - - of 0xAF: - # XOR A - # Logical XOR against (register) A - cpu.r.a = (cpu.r.a xor cpu.r.a) and 255 # If result is bigger than 255, will be set to 0 - cpu.changeFlags(Z = >>(cpu.r.a == 0), H = FUnset, C = FUnset) - cpu.r.clock.m = 1 - - of 0xC1: - # POP BC - # Pop 16-bit value into BC - POPqq(cpu, b, c) - of 0xD1: - # POP DE - POPqq(cpu, d, e) - of 0xE1: - # POP HL - POPqq(cpu, H, L) - of 0xF1: - # POP AF - POPqq(cpu, a, f) - of 0xC5: - # PUSH BC - # Push 16-bit BC onto stack. - PUSHqq(cpu, b, c) - of 0xD5: - # PUSH DE - PUSHqq(cpu, d, e) - of 0xE5: - # PUSH HL - PUSHqq(cpu, H, L) - of 0xF5: - # PUSH AF - PUSHqq(cpu, a, f) - - of 0xC9: - # RET - # Return to calling routine. - cpu.r.pc = cpu.mem.readWord(cpu.r.sp) - cpu.r.sp.inc(2) - cpu.r.clock.m = 3 - - of 0xCB: - # Extended Ops - let extop = cpu.mem.readByte(cpu.r.pc) - cpu.r.pc.inc - case extop - of 0x11: - # RL C - # Rotate C left. - RLr(cpu, c) - of 0x7C: - # BIT 7, H - # Test whether bit 7 of H is zero - cpu.changeFlags(Z = >>((cpu.r.h and (1 shl 7)) == 0), H = FSet, N = FUnset) - cpu.r.clock.m = 2 - else: - echo "Unknown extended op: 0x", extop.toHex(2) - assert false - - of 0xCD: - # CALL nn - # Call routine at 16-bit location - cpu.r.sp.dec(2) - - # We pushing pc+2 onto the stack because the next two bits are used. Below next line. - cpu.mem.writeWord(cpu.r.sp, cpu.r.pc+2) - cpu.r.pc = cpu.mem.readWord(cpu.r.pc) - cpu.r.clock.m = 5 - of 0xE0: - # LDH (0xFF00 + n), A - # Save A at address pointed to by (0xFF00 + 8-bit immediate). - cpu.mem.writeByte(0xFF00 + cpu.mem.readByte(cpu.r.pc), cpu.r.a) - cpu.r.pc.inc - cpu.r.clock.m = 3 - - of 0xE2: - # LDH (0xFF00 + C), A - # Save A at address pointed to by 0xFF00+C - cpu.mem.writeByte(0xFF00 + cpu.r.c, cpu.r.a) - cpu.r.clock.m = 2 - - of 0xFE: - # CP n; compare 8-bit immediate against A. - # TODO: This may be wrong. Review. - - var n = cpu.mem.readByte(cpu.r.pc) - var sum = cpu.r.a - n - let isNegative = sum < 0 - sum = sum and 0xFF - - cpu.r.pc.inc - cpu.changeFlags(C = >>isNegative, Z = >>(sum == 0), N = FSet, - H = >>((sum and 0xF) > (cpu.r.a and 0xF))) - cpu.r.clock.m = 2 - - of 0xEA: - # LD (nn), A; Save A at given 16-bit address. - cpu.mem.writeByte(cpu.mem.readWord(cpu.r.pc), cpu.r.a) - cpu.r.pc.inc(2) - cpu.r.clock.m = 4 - - of 0x40 .. 0x45, 0x50 .. 0x55, 0x60 .. 0x65, 0x47 .. 0x4D, 0x57 .. 0x5D, - 0x67 .. 0x6D, 0x78 .. 0x7D, 0x4F, 0x5F, 0x6F, 0x7F: - # Simple LD instructions. (Copy register1 to register2) - LDSimple(cpu, opcode) - - else: - echo "Unknown opcode: 0x", opcode.toHex(2) - assert false - -proc next*(cpu: PCPU) = - cpu.exec() - cpu.mem.gpu.next(cpu.r.clock.m) - - -when isMainModule: - var cpu = newCpu(mem.load("/home/dom/code/nimrod/gbemulator/Pokemon_Red.gb")) - while True: - cpu.next() \ No newline at end of file diff --git a/tests/manyloc/gbemulator/cpu.nimrod.cfg b/tests/manyloc/gbemulator/cpu.nimrod.cfg deleted file mode 100644 index 1119d356b..000000000 --- a/tests/manyloc/gbemulator/cpu.nimrod.cfg +++ /dev/null @@ -1,2 +0,0 @@ -# This config file marks 'cpu' as the main module. - diff --git a/tests/manyloc/gbemulator/gpu.nim b/tests/manyloc/gbemulator/gpu.nim deleted file mode 100644 index 1f59d7904..000000000 --- a/tests/manyloc/gbemulator/gpu.nim +++ /dev/null @@ -1,110 +0,0 @@ -# Part of the Nimrod Gameboy emulator. -# Copyright (C) Dominik Picheta. - -import colors, strutils - -type - TGPUMode = enum - HBlank = 0, VBlank = 1, OAMRead = 2, VRAMRead = 3, - - TBGTile = enum - TileSet0, TileSet1 - TBGMap = enum - TileMap0, TileMap1 - - TPaletteKind = enum - PaletteBG, PaletteObj, PaletteObj1 - - PGPU* = ref object - vram*: array[0 .. 8191, int32] - mode*: TGPUMode - clock: int32 - line: int - palette: array[TPaletteKind, array[0..3, TColor]] # 4 colors. 0-1 (Lightest), 7-8 (Darkest) - scrollY, scrollX: int32 - bgtilemap: TBGMap - bgtileset: TBGTile - -proc newGPU*(): PGPU = - new(result) - - # Set default palette - result.palette[PaletteBG] = [colWhite, rgb(192, 192, 192), rgb(96, 96, 96), colBlack] - -proc getTileAddr(gpu: PGPU, index: int32): int = - ## Returns the address of the beginning of the tile at ``index``. - case gpu.bgtileset - of TileSet0: - return 0x1000+(index*16) # Each tile is 2 bytes (16 bits) - of TileSet1: - return 0x0000+(index*16) - -proc getTileRow(gpu: PGPU, index: int32): array[0..7, int32] = - let tileAddr = getTileAddr(gpu, index) - let y = (gpu.line + gpu.scrollY) and 7 - for px in 0 .. 7: - result[px] = gpu.vram[tileAddr+px] or (gpu.vram[tileAddr+px+1] shl 8) - -proc renderLine*(gpu: PGPU) = - echo("Render Line: ", gpu.line, " scrollX: ", gpu.scrollX, " scrollY: ", gpu.scrollY) - var mapOffset = if gpu.bgTileMap == TileMap0: 0x1800 else: 0x1C00 - # Get the line of tiles to use. - mapOffset.inc(((gpu.line + gpu.scrollY) and 0xFF) shr 3) - echo("MapOffset: ", mapOffset.toHex(4)) - - let lineOffset = (gpu.scrollX shr 3) # Which tile to start with in the map line - - # Get tile index from background map - var tileIndex = gpu.vram[mapOffset + lineOffset] - - echo("Tile index: ", tileIndex) - - echo("bgtileset: ", gpu.bgtileset) - - - let tile = getTileRow(gpu, tileIndex) - - let y = (gpu.line + gpu.scrollY) and 7 - let x = gpu.scrollX and 7 - let surfaceOffset = gpu.line * 160 * 4 - -proc next*(gpu: PGPU, time: int) = - gpu.clock.inc(time) - #echo("GPU Mode: ", gpu.mode) - case gpu.mode - of OAMRead: - if gpu.clock >= 80: - # Enter VRAMRead - gpu.mode = VRAMRead - gpu.clock = 0 - of VRAMRead: - if gpu.clock >= 172: - # Enter HBlank - gpu.mode = HBlank - gpu.clock = 0 - - # Render scanline - gpu.renderLine() - of HBlank: - if gpu.clock >= 204: - gpu.clock = 0 - gpu.line.inc - #echo("HBlank line: ", gpu.line) - if gpu.line == 143: - # We reached the bottom edge of the screen (screen is 144 pixels in height.) - # Enter VBlank - gpu.mode = VBlank - - # TODO: Render surface on screen. - else: - gpu.mode = OAMRead - of VBlank: - if gpu.clock >= 456: - gpu.clock = 0 - - # TODO: according to ref, line should be increased and, should wait - # for line to be greater than 153? then restart the line and mode? - echo("Vblank done. Line = ", gpu.line) - gpu.mode = OAMRead - gpu.line = 0 - \ No newline at end of file diff --git a/tests/manyloc/gbemulator/mem.nim b/tests/manyloc/gbemulator/mem.nim deleted file mode 100644 index 953f97dfe..000000000 --- a/tests/manyloc/gbemulator/mem.nim +++ /dev/null @@ -1,173 +0,0 @@ -# Part of the Nimrod Gameboy emulator. -# Copyright (C) Dominik Picheta. - -import os, strutils, unsigned -import gpu - -type - PMem* = ref object - rom: string - gameName*: string - cartType*, romSize*, ramSize*: char - bios: array[0 .. 255, int32] # 255 Bytes - extRAM: array[0 .. 8191, int32] # 8KB - workRAM: array[0 .. 8191, int32] # 8KB - zeroRAM: array[0 .. 127, int32] - gpu*: PGPU - -proc hexdump(s: string) = - for c in s: - stdout.write(c.ord.BiggestInt.toHex(2) & " ") - echo("") - -const - NintendoGraphic = - [ - '\xCE', '\xED', '\x66', '\x66', '\xCC', '\x0D', '\x00', '\x0B', - '\x03', '\x73', '\x00', '\x83', '\x00', '\x0C', '\x00', '\x0D', - '\x00', '\x08', '\x11', '\x1F', '\x88', '\x89', '\x00', '\x0E', - '\xDC', '\xCC', '\x6E', '\xE6', '\xDD', '\xDD', '\xD9', '\x99', - '\xBB', '\xBB', '\x67', '\x63', '\x6E', '\x0E', '\xEC', '\xCC', - '\xDD', '\xDC', '\x99', '\x9F', '\xBB', '\xB9', '\x33', '\x3E' - ] - bios = [ - 0x31'i32, 0xFE, 0xFF, 0xAF, 0x21, 0xFF, 0x9F, 0x32, 0xCB, 0x7C, 0x20, 0xFB, 0x21, 0x26, 0xFF, 0x0E, - 0x11, 0x3E, 0x80, 0x32, 0xE2, 0x0C, 0x3E, 0xF3, 0xE2, 0x32, 0x3E, 0x77, 0x77, 0x3E, 0xFC, 0xE0, - 0x47, 0x11, 0x04, 0x01, 0x21, 0x10, 0x80, 0x1A, 0xCD, 0x95, 0x00, 0xCD, 0x96, 0x00, 0x13, 0x7B, - 0xFE, 0x34, 0x20, 0xF3, 0x11, 0xD8, 0x00, 0x06, 0x08, 0x1A, 0x13, 0x22, 0x23, 0x05, 0x20, 0xF9, - 0x3E, 0x19, 0xEA, 0x10, 0x99, 0x21, 0x2F, 0x99, 0x0E, 0x0C, 0x3D, 0x28, 0x08, 0x32, 0x0D, 0x20, - 0xF9, 0x2E, 0x0F, 0x18, 0xF3, 0x67, 0x3E, 0x64, 0x57, 0xE0, 0x42, 0x3E, 0x91, 0xE0, 0x40, 0x04, - 0x1E, 0x02, 0x0E, 0x0C, 0xF0, 0x44, 0xFE, 0x90, 0x20, 0xFA, 0x0D, 0x20, 0xF7, 0x1D, 0x20, 0xF2, - 0x0E, 0x13, 0x24, 0x7C, 0x1E, 0x83, 0xFE, 0x62, 0x28, 0x06, 0x1E, 0xC1, 0xFE, 0x64, 0x20, 0x06, - 0x7B, 0xE2, 0x0C, 0x3E, 0x87, 0xF2, 0xF0, 0x42, 0x90, 0xE0, 0x42, 0x15, 0x20, 0xD2, 0x05, 0x20, - 0x4F, 0x16, 0x20, 0x18, 0xCB, 0x4F, 0x06, 0x04, 0xC5, 0xCB, 0x11, 0x17, 0xC1, 0xCB, 0x11, 0x17, - 0x05, 0x20, 0xF5, 0x22, 0x23, 0x22, 0x23, 0xC9, 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, - 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, - 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, - 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E, 0x3c, 0x42, 0xB9, 0xA5, 0xB9, 0xA5, 0x42, 0x4C, - 0x21, 0x04, 0x01, 0x11, 0xA8, 0x00, 0x1A, 0x13, 0xBE, 0x20, 0xFE, 0x23, 0x7D, 0xFE, 0x34, 0x20, - 0xF5, 0x06, 0x19, 0x78, 0x86, 0x23, 0x05, 0x20, 0xFB, 0x86, 0x20, 0xFE, 0x3E, 0x01, 0xE0, 0x50 - ] - -proc verifyBytes[R](raw: var string, bytes: array[R, char], start: int): bool = - result = true - for i in 0 .. bytes.high: - if raw[i+start] != bytes[i]: - return false - -proc getBytes(raw: var string, dest: var string, slice: TSlice[int]) = - assert slice.a < slice.b - assert slice.a > 0 - let len = slice.b - slice.a - dest = newString(len) - for i in 0 .. len: - dest[i] = raw[slice.a + i] - -proc load*(path: string): PMem = - new result - result.rom = readFile(path) - - # Verify Nintendo graphic - # TODO: Proper exceptions. - #doAssert result.rom.verifyBytes(NintendoGraphic, 0x0104) - - # Gather meta data. - result.gameName = result.rom[0x0134 .. 0x0142] - echo("Game is: " & result.gameName) - - doAssert result.rom[0x0143].ord != 0x80 # 0x80 here means the ROM is for Color GB. - - result.cartType = result.rom[0x0147] - result.romSize = result.rom[0x0148] - result.ramSize = result.rom[0x0149] - result.bios = bios - - result.GPU = newGPU() - -proc reset*(mem: PMem) = - for i in 0..mem.extRam.len: mem.extRam[i] = 0 - for i in 0..mem.workRam.len: mem.workRam[i] = 0 - -proc readByte*(mem: PMem, address: int32): int32 = - if (address in {0x104 .. 0x133}): - echo("Bios is accessing the location of the nintendo logo: ", address.toHex(4)) - case (address and 0xF000) - of 0x0000: - # BIOS - if address > mem.bios.high: return 0 # TODO: Correct? - return mem.bios[address] - of 0x1000, 0x2000, 0x3000: - return mem.rom[address.int].ord - of 0x4000, 0x5000, 0x6000, 0x7000: - # ROM Bank 1 - of 0x8000, 0x9000: - # VRAM - return mem.GPU.vram[address and 0x1FFF] - of 0xF000: - case address and 0x0F00 - of 0x0F00: - if address > 0xFF7F: - return mem.zeroRAM[address and 0x007F] - - assert false - else: - assert false - else: - echo("Read ", address.toHex(4)) - assert false - -proc readWord*(mem: PMem, address: int32): int32 = - return readByte(mem, address) or (readByte(mem, address+1) shl 8) - -proc writeByte*(mem: PMem, address: int32, b: int32) = - case (address and 0xF000) - of 0x8000, 0x9000: - # VRAM - # Each pixel is 2 bits. VRAM is the tileset. - echo("VRAM. Address: 0x", toHex(address, 4), " Value: ", toHex(b, 4)) - mem.GPU.vram[address and 0x1FFF] = b - - of 0xF000: - case address and 0x0F00 - of 0x0F00: - if address > 0xFF7F: - #echo("ZeroRam. Address: ", toHex(address, 4), " Value: ", toHex(b, 4)) - mem.zeroRAM[address and 0x007F] = b - return - - case address - of 0xFF11: - # TODO: - echo("Sound Mode 1 register (0xFF11): ", b.toHex(4)) - of 0xFF26: - # TODO: - echo("Sound on/off (0xFF26): ", b.toHex(4)) - of 0xFF47: - # TODO: - echo("BG Palette (0xFF47): ", b.toHex(4)) - else: - echo("Interrupts. Address: 0x", toHex(Address, 4), " Value: ", toHex(b, 4)) - else: - echo("0xF000. Address: 0x", toHex(Address, 4), " Value: ", toHex(b, 4)) - - else: - echo("writeByte. Address: 0x", toHex(address, 4), " Value: ", toHex(b, 4)) - -proc writeWord*(mem: PMem, address: int32, w: int32) = - mem.writeByte(address, w and 255) - mem.writeByte(address+1, w shr 8) - -when isMainModule: - var rom = load("/home/dom/code/nimrod/gbemulator/Pokemon_Red.gb") - - - - - - - - - - - - \ No newline at end of file diff --git a/tests/manyloc/gbemulator/readme.markdown b/tests/manyloc/gbemulator/readme.markdown deleted file mode 100644 index 796191224..000000000 --- a/tests/manyloc/gbemulator/readme.markdown +++ /dev/null @@ -1,12 +0,0 @@ -# gbemulator - -Inspired by the Rust NES emulator I have decided to write a Gameboy emulator in -my favourite programming language. - -## References - -http://www.devrs.com/gb/files/gbspec.txt -http://www.zilog.com/docs/z80/um0080.pdf -https://github.com/Two9A/jsGB/blob/master/js -https://github.com/grantgalitz/GameBoy-Online/blob/master/js/GameBoyCore.js -http://imrannazar.com/Gameboy-Z80-Opcode-Map \ No newline at end of file diff --git a/tests/run/tasynciossl.nim b/tests/run/tasynciossl.nim index e5fb9610c..fbed46efb 100644 --- a/tests/run/tasynciossl.nim +++ b/tests/run/tasynciossl.nim @@ -26,7 +26,7 @@ proc swarmConnect(s: PAsyncSocket) = proc serverRead(s: PAsyncSocket) = var line = "" - assert s.recvLine(line) + assert s.readLine(line) if line != "": #echo(line) if line.startsWith("Message "): |