Next-generation FPGA SoC toolkit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

simplesoc_ecp5.py 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import os
  2. import argparse
  3. import struct
  4. from nmigen import *
  5. from nmigen.back import pysim
  6. from nmigen_boards.versa_ecp5 import VersaECP5Platform
  7. from heavycomps import uart, wishbone
  8. from minerva.core import Minerva
  9. class SimpleWishboneSerial(Elaboratable):
  10. def __init__(self, tx, sys_clk_freq, baudrate=115200):
  11. self.tx = tx
  12. self.bus = wishbone.Interface()
  13. self.ftw = round(2**32*baudrate/sys_clk_freq)
  14. def elaborate(self, platform):
  15. m = Module()
  16. m.submodules.tx = tx = uart.RS232TX(self.ftw)
  17. m.d.comb += [
  18. tx.stb.eq(self.bus.cyc & self.bus.stb & self.bus.we),
  19. tx.data.eq(self.bus.dat_w),
  20. self.bus.ack.eq(tx.ack),
  21. self.tx.eq(tx.tx)
  22. ]
  23. return m
  24. class Top(Elaboratable):
  25. def __init__(self, firmware, simulate):
  26. self.firmware = firmware
  27. self.simulate = simulate
  28. def elaborate(self, platform):
  29. m = Module()
  30. if self.simulate:
  31. io_user_led = Signal()
  32. io_uart_tx = Signal()
  33. else:
  34. cd_sync = ClockDomain(reset_less=True)
  35. m.domains += cd_sync
  36. m.d.comb += cd_sync.clk.eq(platform.request("clk100").i)
  37. io_user_led = platform.request("led").o
  38. io_uart_tx = platform.request("uart").tx.o
  39. counter = Signal(27)
  40. m.d.sync += counter.eq(counter + 1)
  41. m.d.comb += io_user_led.eq(counter[-1])
  42. m.submodules.cpu = cpu = Minerva(with_icache=False, with_dcache=False, with_muldiv=False)
  43. m.submodules.ram = ram = wishbone.SRAM(Memory(width=32, depth=1024, init=self.firmware))
  44. m.submodules.uart = uart = SimpleWishboneSerial(io_uart_tx, 100e6)
  45. m.submodules.con = con = wishbone.InterconnectShared(
  46. [cpu.ibus, cpu.dbus],
  47. [
  48. (lambda a: ~a[20], ram.bus),
  49. (lambda a: a[20], uart.bus)
  50. ], register=True)
  51. return m
  52. def read_firmware(file):
  53. firmware = []
  54. with open(file, "rb") as f:
  55. while True:
  56. word = f.read(4)
  57. if len(word) < 4:
  58. break
  59. firmware.append(struct.unpack("<I", word)[0])
  60. return firmware
  61. def main():
  62. parser = argparse.ArgumentParser()
  63. parser.add_argument("--simulate", action="store_true")
  64. parser.add_argument("firmware_bin")
  65. parser.add_argument("build_dir")
  66. args = parser.parse_args()
  67. firmware = read_firmware(args.firmware_bin)
  68. top = Top(firmware, args.simulate)
  69. if args.simulate:
  70. os.makedirs(args.build_dir, exist_ok=True)
  71. with pysim.Simulator(top,
  72. vcd_file=open(os.path.join(args.build_dir, "simplesoc.vcd"), "w"),
  73. gtkw_file=open(os.path.join(args.build_dir, "simplesoc.gtkw"), "w")) as sim:
  74. sim.add_clock(1e-6)
  75. sim.run_until(1000e-6, run_passive=True)
  76. else:
  77. VersaECP5Platform().build(top, build_dir=args.build_dir)
  78. if __name__ == "__main__":
  79. main()