Here is one in less than 200 lines of python: https://github.com/s-holst/tinyrv .
It uses machine-readable specs from https://github.com/riscv/riscv-opcodes ; yet I needed to extract immediate bit scrambling from their LaTeX sources :). I wonder if there is an easier way. Anyways, the opcode semantics are hand-coded and it simulates enough to boot linux.
If you only want to simulate the core instruction, and perhaps the Multiply extension or so, and only plan to support single threaded operation, then the natural language spec ain't so bad.