Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: whitequark/Boneless-CPU
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 26d7202704c4
Choose a base ref
...
head repository: whitequark/Boneless-CPU
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 455dc555ef6b
Choose a head ref
  • 3 commits
  • 8 files changed
  • 1 contributor

Commits on Dec 24, 2018

  1. Copy the full SHA
    92fee90 View commit details
  2. Copy the full SHA
    9bef717 View commit details
  3. Add Python package.

    whitequark committed Dec 24, 2018
    Copy the full SHA
    455dc55 View commit details
Showing with 612 additions and 436 deletions.
  1. +4 −4 boneless/__init__.py
  2. +131 −0 boneless/disasm.py
  3. 0 boneless/gateware/__init__.py
  4. +422 −0 boneless/gateware/core_fsm.py
  5. +4 −428 boneless/{gateware.py → gateware/test_core.py}
  6. +6 −4 boneless/instr.py
  7. +21 −0 boneless/test_disasm.py
  8. +24 −0 setup.py
8 changes: 4 additions & 4 deletions boneless/__init__.py
Original file line number Diff line number Diff line change
@@ -200,19 +200,19 @@
# Memory instructions
# -------------------
#
# Mnemonic: LD Rd, Ra, off
# Mnemonic: LD Rd, Ra, ±off
# Operation: Rd ← mem[Ra+off]
#
# Mnemonic: LDX Rd, Ra, off
# Mnemonic: LDX Rd, Ra, ±off
# Operation: Rd ← ext[Ra+off]
#
# Mnemonic: LDI Rd, ±off
# Operation: Rd ← mem[PC+off]
#
# Mnemonic: ST Rs, Ra, off
# Mnemonic: ST Rs, Ra, ±off
# Operation: mem[Ra+off] ← Rs
#
# Mnemonic: STX Rs, Ra, off
# Mnemonic: STX Rs, Ra, ±off
# Operation: ext[Ra+off] ← Rs
#
# Mnemonic: STI Rs, ±off
131 changes: 131 additions & 0 deletions boneless/disasm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from .opcode import *


__all__ = ["disassemble"]


def bits(word, start, end=None, sign=False):
if end is None:
end = start + 1
value = (word >> start) & ((1 << (end - start)) - 1)
if sign and value & (1 << (end - start - 1)):
return -((1 << (end - start)) - value)
else:
return value


def disassemble(insn, python=False):
if python:
l, r = "()"
else:
l = r = ""

i_class = bits(insn, 12, 16)
i_code1 = bits(insn, 11, 12)
i_code2 = bits(insn, 11, 13)
i_code3 = bits(insn, 11, 14)
i_code5 = bits(insn, 11, 16)
i_type1 = bits(insn, 0, 1)
i_type2 = bits(insn, 0, 2)
i_shift = bits(insn, 1, 5)
i_imm5 = bits(insn, 0, 5, sign=True)
i_imm8 = bits(insn, 0, 8, sign=True)
i_imm11 = bits(insn, 0, 11, sign=True)
i_regX = bits(insn, 2, 5)
i_regY = bits(insn, 5, 8)
i_regZ = bits(insn, 8, 11)
i_store = bits(insn, 11)
i_ext = bits(insn, 12)
i_flag = bits(insn, 11)
i_cond = bits(insn, 12, 15)

if i_code5 == OPCODE_LOGIC:
if i_type2 == OPTYPE_AND:
return "AND {}R{}, R{}, R{}{}".format(l, i_regZ, i_regY, i_regX, r)
if i_type2 == OPTYPE_OR:
return "OR {}R{}, R{}, R{}{}".format(l, i_regZ, i_regY, i_regX, r)
if i_type2 == OPTYPE_XOR:
return "XOR {}R{}, R{}, R{}{}".format(l, i_regZ, i_regY, i_regX, r)
if i_code5 == OPCODE_ARITH:
if i_type2 == OPTYPE_ADD:
return "ADD {}R{}, R{}, R{}{}".format(l, i_regZ, i_regY, i_regX, r)
if i_type2 == OPTYPE_SUB:
return "SUB {}R{}, R{}, R{}{}".format(l, i_regZ, i_regY, i_regX, r)
if i_type2 == OPTYPE_CMP:
return "CMP {}R{}, R{}{}".format(l, i_regY, i_regX, r)
if i_code5 == OPCODE_SHIFT_L:
if i_type1 == OPTYPE_SLL:
return "SLL {}R{}, R{}, {}{}".format(l, i_regZ, i_regY, i_shift, r)
if i_type1 == OPTYPE_ROT:
return "ROT {}R{}, R{}, {}{}".format(l, i_regZ, i_regY, i_shift, r)
if i_code5 == OPCODE_SHIFT_R:
if i_type1 == OPTYPE_SRL:
return "SRL {}R{}, R{}, {}{}".format(l, i_regZ, i_regY, i_shift, r)
if i_type1 == OPTYPE_SRA:
return "SRA {}R{}, R{}, {}{}".format(l, i_regZ, i_regY, i_shift, r)
if i_code5 == OPCODE_LD:
return "LD {}R{}, R{}, {:+}{}".format(l, i_regZ, i_regY, i_imm5, r)
if i_code5 == OPCODE_ST:
return "ST {}R{}, R{}, {:+}{}".format(l, i_regZ, i_regY, i_imm5, r)
if i_code5 == OPCODE_LDX:
return "LDX {}R{}, R{}, {:+}{}".format(l, i_regZ, i_regY, i_imm5, r)
if i_code5 == OPCODE_STX:
return "STX {}R{}, R{}, {:+}{}".format(l, i_regZ, i_regY, i_imm5, r)
if i_code5 == OPCODE_MOVL:
return "MOVL {}R{}, {}{}".format(l, i_regZ, i_imm8 & 0xff, r)
if i_code5 == OPCODE_MOVH:
return "MOVH {}R{}, {}{}".format(l, i_regZ, i_imm8 & 0xff, r)
if i_code5 == OPCODE_MOVA:
return "MOVA {}R{}, {:+}{}".format(l, i_regZ, i_imm8, r)
if i_code5 == OPCODE_ADDI:
return "ADDI {}R{}, {}{}".format(l, i_regZ, i_imm8, r)
if i_code5 == OPCODE_LDI:
return "LDI {}R{}, {:+}{}".format(l, i_regZ, i_imm8, r)
if i_code5 == OPCODE_STI:
return "STI {}R{}, {:+}{}".format(l, i_regZ, i_imm8, r)
if i_code5 == OPCODE_JAL:
return "JAL {}R{}, {:+}{}".format(l, i_regZ, i_imm8, r)
if i_code5 == OPCODE_JR:
return "JR {}R{}, {:+}{}".format(l, i_regZ, i_imm8, r)
if i_code5 == OPCODE_J:
return "J {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JNZ:
return "JNZ {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JZ:
return "JZ {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JNS:
return "JNS {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JS:
return "JS {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JNO:
return "JNO {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JO:
return "JO {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JULT:
return "JULT {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JUGE:
return "JUGE {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JUGT:
return "JUGT {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JULE:
return "JULE {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JSGE:
return "JSGE {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JSLT:
return "JSLT {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JSGT:
return "JSGT {}{:+}{}".format(l, i_imm11, r)
if i_code5 == OPCODE_JSLE:
return "JSLE {}{:+}{}".format(l, i_imm11, r)

return "ILL {}0x{:04x}{}".format(l, insn, r)


def main():
import fileinput
for line in fileinput.input():
print(disassemble(int(line, 16)), flush=True)


if __name__ == "__main__":
main()
Empty file added boneless/gateware/__init__.py
Empty file.
422 changes: 422 additions & 0 deletions boneless/gateware/core_fsm.py

Large diffs are not rendered by default.

432 changes: 4 additions & 428 deletions boneless/gateware.py → boneless/gateware/test_core.py

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions boneless/instr.py
Original file line number Diff line number Diff line change
@@ -5,10 +5,10 @@

__all__ = [
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
"ADD", "ADDI", "AND", "CMP", "J", "JAL", "JC", "JE", "JNC", "JNE", "JNO", "JNS", "JNZ", "JO",
"JR", "JS", "JSGE", "JSGT", "JSLE", "JSLT", "JUGE", "JUGT", "JULE", "JULT", "JZ", "LD", "LDI",
"LDX", "MOV", "MOVA", "MOVH", "MOVI", "MOVL", "NOP", "OR", "ROT", "ROL", "ROR", "SLL", "SRA",
"SRL", "ST", "STI", "STX", "SUB", "SUBI", "XOR",
"ADD", "ADDI", "AND", "CMP", "ILL", "J", "JAL", "JC", "JE", "JNC", "JNE", "JNO", "JNS", "JNZ",
"JO", "JR", "JS", "JSGE", "JSGT", "JSLE", "JSLT", "JUGE", "JUGT", "JULE", "JULT", "JZ",
"LD", "LDI", "LDX", "MOV", "MOVA", "MOVH", "MOVI", "MOVL", "NOP", "OR", "ROT", "ROL", "ROR",
"SLL", "SRA", "SRL", "ST", "STI", "STX", "SUB", "SUBI", "XOR",
"L", "assemble",
]

@@ -126,6 +126,8 @@ def MOVI(rd, imm16):
return MOVH(rd, (imm16 >> 8) + ((imm16 >> 7) & 1)) + \
[I_FORMAT(OPCODE_ADDI, rd, imm16 & 0xff, u=True)]

def ILL(insn): return [insn & 0xffff]


def L(label): return label

21 changes: 21 additions & 0 deletions boneless/test_disasm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import unittest

from .disasm import disassemble
from .instr import *


class DisassemblerTestCase(unittest.TestCase):
def test_exhaustive(self):
for insn in range(0, 0x10000):
text_insn = disassemble(insn, python=False)
code_insn = disassemble(insn, python=True)
try:
roundtrip_insn = eval(code_insn)[0]
code_insn_2 = disassemble(roundtrip_insn, python=True)
roundtrip_insn_2 = eval(code_insn_2)[0]
except Exception as e:
msg = "(instruction {}, encoding {:04x}) {}".format(code_insn, insn, str(e))
raise self.failureException(msg).with_traceback(e.__traceback__) from None
if roundtrip_insn != roundtrip_insn_2:
self.fail("instruction {}: encoding {:04x}, roundtrip {:04x}"
.format(code_insn, insn, roundtrip_insn))
24 changes: 24 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from setuptools import setup, find_packages


setup(
name="boneless",
version="0.1",
author="whitequark",
author_email="whitequark@whitequark.org",
description="Resource-efficient 16-bit CPU architecture for FPGA control plane",
#long_description="""TODO""",
license="0-clause BSD License",
install_requires=["nmigen"],
packages=find_packages(),
project_urls={
#"Documentation": "https://glasgow.readthedocs.io/",
"Source Code": "https://github.com/whitequark/Boneless-CPU",
"Bug Tracker": "https://github.com/whitequark/Boneless-CPU/issues",
},
entry_points={
"console_scripts": [
"boneless-disasm = boneless.disasm:main"
]
}
)