videocodecs.py 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. # Copyright (c) 2024 Victor Suarez Rovere <suarezvictor@gmail.com>
  2. from migen import *
  3. from litex.soc.integration.soc import AutoCSR, CSRStorage, CSRStatus
  4. from litedram.frontend.dma import LiteDRAMDMAWriter
  5. from litedram.frontend.dma import LiteDRAMDMAReader
  6. class JPEGDecoder(Module, AutoCSR):
  7. def __init__(self, rdport, wrport, DHT=True, output_alpha=0xFF, debug=False):
  8. assert(rdport.data_width == 32)
  9. assert(wrport.data_width == 32)
  10. self.submodules.reader = reader = LiteDRAMDMAReader(rdport, with_csr=True)
  11. self.submodules.writer = writer = LiteDRAMDMAWriter(wrport, with_csr=False)
  12. source = self.reader.source
  13. self.writer_base = CSRStorage(wrport.address_width)
  14. self.writer_stride = CSRStorage(16)
  15. self.idle_status = CSRStatus()
  16. self.outport_width = CSRStatus(16)
  17. self.outport_height = CSRStatus(16)
  18. self.outport_x = CSRStatus(16)
  19. self.outport_y = CSRStatus(16)
  20. self.outport_pixel_offset = CSRStatus(wrport.address_width)
  21. pixel_offset = self.outport_pixel_offset.status
  22. inport_accept = Signal()
  23. inport_ready = Signal()
  24. output_idle = Signal()
  25. outport_valid = Signal()
  26. outport_pixel_x = self.outport_x.status
  27. outport_pixel_y = self.outport_y.status
  28. outport_pixel_r = Signal(8)
  29. outport_pixel_g = Signal(8)
  30. outport_pixel_b = Signal(8)
  31. alpha_value = Constant(output_alpha)
  32. self.done = Signal(reset=1)
  33. out_done = Signal(reset=0)
  34. reader_last = Signal(reset=0)
  35. self.sync += If(reader._enable.re & reader.enable & self.done, reader_last.eq(0), out_done.eq(0), self.done.eq(0), Display("start"))
  36. self.sync += If(reader._enable.re & reader.enable, reader_last.eq(0))
  37. self.sync += If(reader._done.status & ~reader_last, reader_last.eq(1), Display("_offset %x, _length %x", reader._offset.status, reader._length.storage))
  38. self.sync += If(reader_last & ~output_idle & ~out_done, out_done.eq(1), Display("out_done %d, %d", outport_pixel_x, outport_pixel_y))
  39. #self.sync += If(out_done & ~self.done, Display("END %d, %d, valid %d", outport_pixel_x, outport_pixel_y, outport_valid))
  40. self.sync += If(out_done & ~self.done & (outport_pixel_x >= self.outport_width.status-1) & (outport_pixel_y >= self.outport_height.status-1), self.done.eq(~outport_valid),
  41. Display("Done at pixel %d,%d, wxh %d, %d, level %d, valid %d", outport_pixel_x, outport_pixel_y, self.outport_width.status, self.outport_height.status, writer.fifo.level, outport_valid))
  42. self.params = dict(
  43. p_SUPPORT_WRITABLE_DHT = 1 if DHT else 0,
  44. i_clk_i = ClockSignal("sys"),
  45. i_rst_i = ~reader.enable | ResetSignal("sys"),
  46. o_outport_width_o = self.outport_width.status,
  47. o_outport_height_o = self.outport_height.status,
  48. o_inport_accept_o = inport_accept, #ready to accept data (asserted once each 4 bytes)
  49. o_idle_o = output_idle, # useful to know when it's done
  50. i_inport_valid_i = source.valid,
  51. i_inport_data_i = source.data,
  52. i_inport_last_i = Constant(0),
  53. i_inport_strb_i = Constant(0xF),
  54. i_outport_accept_i = writer.sink.ready,
  55. o_outport_valid_o = outport_valid,
  56. o_outport_pixel_x_o = outport_pixel_x,
  57. o_outport_pixel_y_o = outport_pixel_y,
  58. o_outport_pixel_r_o = outport_pixel_r,
  59. o_outport_pixel_g_o = outport_pixel_g,
  60. o_outport_pixel_b_o = outport_pixel_b,
  61. )
  62. self.comb += [
  63. writer.sink.valid.eq(outport_valid), #write strobe
  64. pixel_offset.eq(outport_pixel_x + outport_pixel_y * self.writer_stride.storage[2:]),
  65. writer.sink.address.eq(self.writer_base.storage[2:] + pixel_offset),
  66. writer.sink.data.eq(Cat(outport_pixel_r, outport_pixel_g, outport_pixel_b, alpha_value)),
  67. inport_ready.eq(inport_accept | (reader.enable & (reader._offset.status == Constant(0)) )),
  68. source.ready.eq(inport_ready),
  69. self.idle_status.status.eq((self.done & writer.fifo.level==0) | ~reader.enable),
  70. ]
  71. self.specials += Instance("jpeg_core", **self.params)