Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
127
Task/Execute-Computer-Zero/Nim/execute-computer-zero.nim
Normal file
127
Task/Execute-Computer-Zero/Nim/execute-computer-zero.nim
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
import std/strformat
|
||||
|
||||
type
|
||||
OpCode = enum opNOP, opLDA, opSTA, opADD, opSUB, opBRZ, opJMP, opSTP
|
||||
Instruction = byte
|
||||
Address = 0..31
|
||||
# Definition of a computer zero.
|
||||
Computer = object
|
||||
mem: array[Address, byte] # Memory.
|
||||
pc: Address # Program counter.
|
||||
acc: byte # Accumulator.
|
||||
Program = tuple
|
||||
name: string # Name of the program.
|
||||
code: seq[Instruction] # List of instructions.
|
||||
|
||||
proc split(inst: Instruction): tuple[code: OpCode, address: Address] =
|
||||
## Split an instruction into an opCode and a value.
|
||||
(OpCode((inst and 0b11100000u8) shr 5), Address(inst and 0b00011111u8))
|
||||
|
||||
proc toInst(opCode: OpCode; address: int): Instruction =
|
||||
## Build an instruction with given opcode and value.
|
||||
if address notin Address.low..Address.high:
|
||||
raise newException(ValueError, "address out of range.")
|
||||
byte(opCode) shl 5 or byte(address)
|
||||
|
||||
# Functions to build instructions.
|
||||
func NOP(n: int): Instruction = toInst(opNOP, n)
|
||||
func LDA(n: int): Instruction = toInst(opLDA, n)
|
||||
func STA(n: int): Instruction = toInst(opSTA, n)
|
||||
func ADD(n: int): Instruction = toInst(opADD, n)
|
||||
func SUB(n: int): Instruction = toInst(opSUB, n)
|
||||
func BRZ(n: int): Instruction = toInst(opBRZ, n)
|
||||
func JMP(n: int): Instruction = toInst(opJMP, n)
|
||||
func STP(n: int): Instruction = toInst(opSTP, n)
|
||||
|
||||
proc reset(comp: var Computer) =
|
||||
## Reset the computer state.
|
||||
comp.mem.reset()
|
||||
comp.pc = 0
|
||||
comp.acc = 0
|
||||
|
||||
proc load(comp: var Computer; program: Program) =
|
||||
## Load a program into a computer.
|
||||
comp.reset()
|
||||
var idx = 0
|
||||
for inst in program.code:
|
||||
comp.mem[idx] = inst
|
||||
inc idx
|
||||
|
||||
proc run(comp: var Computer) =
|
||||
## Run a computer.
|
||||
## The execution starts or resumes at the instruction
|
||||
## at current PC, with current value in the accumulator.
|
||||
while true:
|
||||
let (opCode, address) = comp.mem[comp.pc].split()
|
||||
inc comp.pc
|
||||
case opCode
|
||||
of opNOP:
|
||||
discard
|
||||
of opLDA:
|
||||
comp.acc = comp.mem[address]
|
||||
of opSTA:
|
||||
comp.mem[address] = comp.acc
|
||||
of opADD:
|
||||
comp.acc += comp.mem[address]
|
||||
of opSUB:
|
||||
comp.acc -= comp.mem[address]
|
||||
of opBRZ:
|
||||
if comp.acc == 0:
|
||||
comp.pc = address
|
||||
of opJMP:
|
||||
comp.pc = address
|
||||
of opSTP:
|
||||
break
|
||||
|
||||
proc enterValue(comp: var Computer; value: byte) =
|
||||
## Enter a value into memory at address given by the PC,
|
||||
## then increment the PC.
|
||||
comp.mem[comp.pc] = value
|
||||
inc comp.pc
|
||||
|
||||
|
||||
# Programs are built using the functions NOP, LDA, STA, etc.
|
||||
# To be able to use Uniform Function Call Syntax (i.e. call without parentheses),
|
||||
# all these functions have an argument, even NOP and STP.
|
||||
const
|
||||
Prog1 = (name: "2+2",
|
||||
code: @[LDA 3, ADD 4, STP 0, 2, 2])
|
||||
Prog2 = (name: "7*8",
|
||||
code: @[LDA 12, ADD 10, STA 12, LDA 11, SUB 13, STA 11, BRZ 8, JMP 0,
|
||||
LDA 12, STP 0, 8, 7, 0, 1])
|
||||
Prog3 = (name: "Fibonacci",
|
||||
code: @[LDA 14, STA 15, ADD 13, STA 14, LDA 15, STA 13, LDA 16, SUB 17,
|
||||
BRZ 11, STA 16, JMP 0, LDA 14, STP 0, 1, 1, 0,
|
||||
8, 1])
|
||||
Prog4 = (name: "List",
|
||||
code: @[LDA 13, ADD 15, STA 5, ADD 16, STA 7, NOP 0, STA 14, NOP 0,
|
||||
BRZ 11, STA 15, JMP 0, LDA 14, STP 0, LDA 0, 0, 28,
|
||||
1, 0, 0, 0, 6, 0, 2, 26,
|
||||
5, 20, 3, 30, 1, 22, 4, 24])
|
||||
Prog5 = (name: "Prisoner",
|
||||
code: @[NOP 0, NOP 0, STP 0, NOP 0, LDA 3, SUB 29, BRZ 18, LDA 3,
|
||||
STA 29, BRZ 14, LDA 1, ADD 31, STA 1, JMP 2, LDA 0, ADD 31,
|
||||
STA 0, JMP 2, LDA 3, STA 29, LDA 1, ADD 30, ADD 3, STA 1,
|
||||
LDA 0, ADD 30, ADD 3, STA 0, JMP 2, 0, 1, 3])
|
||||
|
||||
var computer: Computer
|
||||
|
||||
for prog in [Prog1, Prog2, Prog3, Prog4]:
|
||||
computer.load prog
|
||||
computer.run()
|
||||
echo &"Result for {prog.name}: {computer.acc}"
|
||||
|
||||
# "Prog5" is different as it stops and waits for an input from the user.
|
||||
# Input is stored at address 3 (current PC value) and scores are stored at addresses 0 and 1.
|
||||
|
||||
type Action = enum cooperate, defect
|
||||
|
||||
echo &"\nResult for {Prog5.name}:"
|
||||
computer.load Prog5
|
||||
computer.run()
|
||||
|
||||
for round in 1..5:
|
||||
let action = Action(round and 1)
|
||||
computer.enterValue(byte(action))
|
||||
computer.run()
|
||||
echo &"Round {round} Action: {action:9} Player: {computer.mem[0]} Computer: {computer.mem[1]}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue