Snippet content copied to clipboard.
Are you sure to delete this snippet? No, don't delete
paste.mozilla.org allows you to share code snippets and notes with others. These pastes require a link to be viewed; they are not private. Anyone with the link is able to see the paste and also delete it.


Please refrain from sharing personal or sensitive information on this website to avoid it being viewed by other parties.

  1. import sys
  2. sys.dont_write_bytecode = True
  3. import math
  4. from amaranth import *
  5. from amaranth.lib import wiring
  6. from amaranth.lib.wiring import In, Out
  7. from amaranth.lib.enum import Enum
  8. from amaranth.back import verilog
  9. ##############################
  10. ######### Oscillator #########
  11. ##############################
  12. class Sn76489_Oscillator(wiring.Component):
  13. def __init__(self):
  14. print("### Sn76489_Oscillator constructor", file=sys.stderr)
  15. super().__init__({
  16. "I_clk_gate": In(1),
  17. "I_freq": In(10),
  18. "O_voice": Out(1)
  19. })
  20. def elaborate(self, platform):
  21. m = Module()
  22. counter = Signal(10)
  23. out = Signal(1)
  24. with m.If(self.I_clk_gate):
  25. m.d.sync += counter.eq(counter - 1)
  26. with m.If(counter == 0):
  27. m.d.sync += [
  28. out.eq(~out),
  29. counter.eq(self.I_freq)
  30. ]
  31. # for frequency values of 0 and 1 output a constant 1
  32. voice = out | self.I_freq[1:10] == 0
  33. m.d.comb += self.O_voice.eq(voice)
  34. return m
  35. ###################################
  36. ######### Noise generator #########
  37. ###################################
  38. class Sn76489_Noise(wiring.Component):
  39. def __init__(self):
  40. print("### Sn76489_Noise constructor", file=sys.stderr)
  41. super().__init__({
  42. "I_clk_gate": In(1),
  43. "I_ctrl": In(3),
  44. "I_freq": In(10),
  45. "I_reset_voice": In(1),
  46. "O_voice": Out(1),
  47. "O_reset_ack": Out(1)
  48. })
  49. def elaborate(self, platform):
  50. m = Module()
  51. reset = Signal(1)
  52. counter = Signal(10)
  53. shiftreg = Signal(16, init=0x8000)
  54. flipbit = Signal(1)
  55. rate = self.I_ctrl[0:2]
  56. white_noise = self.I_ctrl[2]
  57. with m.If(self.I_clk_gate):
  58. m.d.sync += counter.eq(counter - 1)
  59. with m.If(counter == 0):
  60. m.d.sync += flipbit.eq(~flipbit)
  61. with m.Switch(rate):
  62. with m.Case(0b00):
  63. m.d.sync += counter.eq(0x10)
  64. with m.Case(0b01):
  65. m.d.sync += counter.eq(0x20)
  66. with m.Case(0b10):
  67. m.d.sync += counter.eq(0x40)
  68. with m.Case(0b11):
  69. m.d.sync += counter.eq(self.I_freq)
  70. with m.If(flipbit == 0):
  71. m.d.sync += [
  72. shiftreg[0:15].eq(shiftreg[1:16]),
  73. shiftreg[15].eq(Mux(white_noise, shiftreg[3] ^ shiftreg[0], shiftreg[0]))
  74. ]
  75. with m.If(self.I_reset_voice != reset):
  76. m.d.sync += [
  77. shiftreg.eq(0x8000),
  78. reset.eq(self.I_reset_voice)
  79. ]
  80. m.d.comb += [
  81. self.O_reset_ack.eq(reset),
  82. self.O_voice.eq(shiftreg[0])
  83. ]
  84. return m
  85. #########################
  86. ######### Mixer #########
  87. #########################
  88. class Sn76489_Mixer(wiring.Component):
  89. def __init__(self):
  90. print("### Sn76489_Mixer constructor", file=sys.stderr)
  91. super().__init__({
  92. "I_voices": In(4),
  93. "I_attenuation": In(4 * 4),
  94. "O_pcm": Out(8)
  95. })
  96. def voice_value(self, m, voice, att):
  97. value = Signal(6)
  98. values = [63, 59, 55, 50, 46, 42, 38, 34, 29, 25, 21, 17, 13, 8, 4]
  99. with m.Switch(Cat(att, voice)):
  100. for i in range(len(values)):
  101. with m.Case(0b10000 + i):
  102. m.d.comb += value.eq(values[i])
  103. with m.Default():
  104. m.d.comb += value.eq(0)
  105. return value
  106. def elaborate(self, platform):
  107. m = Module()
  108. values = []
  109. for i in range(4):
  110. voice = self.I_voices[i]
  111. att = self.I_attenuation[i*4:(i*4)+4]
  112. values.append(self.voice_value(m, voice, att))
  113. pcm1 = values[0] + values[1] # 6 bits + 6 bits = 7 bits
  114. pcm2 = values[2] + values[3] # 6 bits + 6 bits = 7 bits
  115. pcm = pcm1 + pcm2 # 7 bits + 7 bits = 8 bits
  116. m.d.comb += self.O_pcm.eq(pcm)
  117. return m
  118. #######################
  119. ######### Top #########
  120. #######################
  121. class Sn76489(wiring.Component):
  122. def __init__(self, clk_target=3579545, clk_infreq=25 * 1000 * 1000):
  123. print("### Sn76489 constructor", file=sys.stderr)
  124. super().__init__({
  125. "I_command": In(8),
  126. "I_write": In(1),
  127. "O_pcm": Out(8),
  128. "O_pcm_new": Out(1)
  129. })
  130. self.clk_divider = round((clk_infreq / clk_target) * 16)
  131. print(f"# SN76489 clk_divider: {self.clk_divider}")
  132. def elaborate(self, platform):
  133. m = Module()
  134. # Clock divider stuff
  135. clk_gate = Signal(1)
  136. clk_counter = Signal(math.ceil(math.log(self.clk_divider, 2)))
  137. m.d.sync += [
  138. clk_gate.eq(0),
  139. clk_counter.eq(clk_counter - 1)
  140. ]
  141. with m.If(clk_counter == 0):
  142. m.d.sync += [
  143. clk_gate.eq(1),
  144. clk_counter.eq(self.clk_divider)
  145. ]
  146. # voice control registers
  147. registers = [
  148. Signal(10), # register 000 - voice 1 freq
  149. Signal(4), # register 001 - voice 1 attenuation
  150. Signal(10), # register 010 - voice 2 freq
  151. Signal(4), # register 011 - voice 2 attenuation
  152. Signal(10), # register 100 - voice 3 freq
  153. Signal(4), # register 101 - voice 3 attenuation
  154. Signal(3), # register 110 - noise control
  155. Signal(4) # register 111 - noise attenuation
  156. ]
  157. # Instantiate three oscillators
  158. oscillators = []
  159. voice_outputs = []
  160. for i in range(3):
  161. osc = Sn76489_Oscillator()
  162. m.submodules += osc
  163. oscillators.append(osc)
  164. osc_output = Signal(1)
  165. voice_outputs.append(osc_output)
  166. m.d.comb += [
  167. osc.I_clk_gate.eq(clk_gate),
  168. osc.I_freq.eq(registers[2*i]), # connect freq registers
  169. osc_output.eq(osc.O_voice)
  170. ]
  171. # Instantiate noise generator
  172. noise = Sn76489_Noise()
  173. m.submodules += noise
  174. noise_reset = Signal(1)
  175. noise_reset_ack = Signal(1)
  176. m.d.comb += [
  177. noise.I_clk_gate.eq(clk_gate),
  178. noise.I_ctrl.eq(registers[6]),
  179. noise.I_freq.eq(registers[4]),
  180. noise.I_reset_voice.eq(noise_reset),
  181. noise_reset_ack.eq(noise.O_reset_ack)
  182. ]
  183. voice_outputs.append(noise.O_voice)
  184. # Instantiate the voice mixer
  185. mixer = Sn76489_Mixer()
  186. m.submodules += mixer
  187. pcm = Signal(8)
  188. m.d.comb += [
  189. mixer.I_voices.eq(Cat(voice_outputs[0], voice_outputs[1], voice_outputs[2], voice_outputs[3])),
  190. mixer.I_attenuation.eq(Cat(registers[1], registers[3], registers[5], registers[7])),
  191. pcm.eq(mixer.O_pcm)
  192. ]
  193. # Update logic for control registers
  194. update = Signal(1)
  195. m.d.sync += update.eq(0)
  196. update_data = Signal(7)
  197. register = Signal(3)
  198. with m.If(self.I_write):
  199. m.d.sync += [
  200. update.eq(1),
  201. update_data.eq(Cat(self.I_command[0:6], self.I_command[7]))
  202. ]
  203. with m.If(self.I_command[7]):
  204. m.d.sync += register.eq(self.I_command[4:7])
  205. with m.If(update):
  206. with m.Switch(Cat(update_data[6], register)):
  207. with m.Case(0b0000):
  208. m.d.sync += registers[0][4:10].eq(update_data[0:6])
  209. with m.Case(0b0001):
  210. m.d.sync += registers[0][0:4].eq(update_data[0:4])
  211. with m.Case(0b0010, 0b0011):
  212. m.d.sync += registers[1].eq(update_data[0:4])
  213. with m.Case(0b0100):
  214. m.d.sync += registers[2][4:10].eq(update_data[0:6])
  215. with m.Case(0b0101):
  216. m.d.sync += registers[2][0:4].eq(update_data[0:4])
  217. with m.Case(0b0110, 0b0111):
  218. m.d.sync += registers[3].eq(update_data[0:4])
  219. with m.Case(0b1000):
  220. m.d.sync += registers[4][4:10].eq(update_data[0:6])
  221. with m.Case(0b1001):
  222. m.d.sync += registers[4][0:4].eq(update_data[0:4])
  223. with m.Case(0b1010, 0b1011):
  224. m.d.sync += registers[5].eq(update_data[0:4])
  225. with m.Case(0b1100, 0b1101):
  226. m.d.sync += [
  227. registers[6].eq(update_data[0:3]),
  228. noise_reset.eq(~noise_reset_ack)
  229. ]
  230. with m.Case(0b1110, 0b1111):
  231. m.d.sync += registers[7].eq(update_data[0:4])
  232. m.d.sync += [
  233. self.O_pcm.eq(pcm),
  234. self.O_pcm_new.eq(clk_gate)
  235. ]
  236. return m
  237. if __name__ == "__main__":
  238. psg = Sn76489()
  239. with open("sn76489.v", "w") as f:
  240. f.write(verilog.convert(psg, name="sn76489"))

Edit this Snippet