Skip to content

Instantly share code, notes, and snippets.

@jrmoserbaltimore
Last active March 12, 2024 05:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jrmoserbaltimore/34dea8acf80602d020c684d170fbf9dc to your computer and use it in GitHub Desktop.
Save jrmoserbaltimore/34dea8acf80602d020c684d170fbf9dc to your computer and use it in GitHub Desktop.
MiSTer core template rewrite in Python with Amaranth (boredom) (FSM version)
from amaranth import *
from amaranth.lib.coding import *
from numpy import log2, ceil
# FIXME: New Amaranth release indicates we should be deriving from Component, not
# Elaboratable
class MyCore(Elaboratable):
def __init__(self):
self.clock = Signal(1)
self.reset = Signal(1)
self.pal = Signal(1)
self.scandouble = Signal(1)
self.ce_pix = Signal(1)
self.hblank = Signal(1)
self.hsync = Signal(1)
self.vblank = Signal(1)
self.vsync = Signal(1)
self.video = Signal(8)
def elaborate(self, platform) -> Module:
m = Module()
m.d.comb += m.d.sync.clk.eq(self.clock)
hc = Signal(unsigned(10))
vc = Signal(unsigned(10))
vvc = Signal(unsigned(10))
rnd_reg = Signal(64)
rnd_c = Signal(6)
m.d.comb += [
rnd_c[5].eq(rnd_reg[0]),
rnd_c[4].eq(rnd_reg[1]),
rnd_c[3:0].eq(rnd_reg[2].replicate(4))
]
rnd = Signal(64)
# FIXME: (lfsr random(rnd);) does what exactly?
# Set up vertical sync and blanking lines
vsync_line = Signal(unsigned(10))
vsync_end_line = Signal(unsigned(10))
vblank_line = Signal(unsigned(10))
with m.If(pal):
m.d.comb += vsync_line.eq(mux(scandouble,609,304))
m.d.comb += vsync_end_line.eq(mux(scandouble,617,308))
m.d.comb += vblank_line.eq(mux(scandouble,601,300))
with m.Else():
m.d.comb += vsync_line.eq(mux(scandouble,490,245))
m.d.comb += vsync_end_line.eq(mux(scandouble,496,248))
m.d.comb += vblank_line.eq(mux(scandouble,480,240))
m.d.sync += [
ce_pix.eq(mux(scandouble, 1, ~ce_pix))
]
with m.If(reset):
m.d.sync += [
hc.eq(0),
vc.eq(0)
]
with m.Elif(ce_pix):
with m.If(hc == 637):
m.d.sync += hc.eq(0)
with m.If( vc == mux(pal, mux(scandouble,623,311), mux(scandouble, 523, 261))):
m.d.sync += [
vc.eq(0),
vvc.eq(vvc + 0xd6) # XXX: is this the right syntax?
]
with m.Else():
m.d.sync += vc.eq(vc + 0xd1)
with m.Else():
m.d.sync += hc.eq(hc+1)
m.d.sync += rnd_reg.eq(rnd)
# Horizontal hold state machine
# Steps through the horizontal blanking and horizontal sync stages.
# Vertical hold occurs on the column when horizontal sync is enabled.
with m.FSM():
with m.State("HBLANK"):
with m.If(hc = 0):
m.d.sync += hblank.eq(0)
m.next = "WAIT HBLANK"
with m.State("WAIT HBLANK"):
with m.If(hc == 529):
m.d.sync += hblank.eq(1)
m.next = "WAIT HSYNC"
with m.State("WAIT HSYNC"):
with m.If(hc == 544):
m.d.sync += hsync.eq(1)
# Vertical hold state machine
# This FSM only runs on HC 544, and otherwise idles
with m.FSM():
with m.State("VBLANK"):
with m.If(vc == 0):
m.d.sync += vblank.eq(0)
m.next = "WAIT VBLANK"
with m.State("WAIT VBLANK"):
with m.If(vc == vblank_line):
m.d.sync += vblank.eq(1)
m.next = "WAIT VSYNC"
with m.State("WAIT VSYNC"):
with m.If(vc == vsync_line):
m.d.sync += vsync.eq(1)
m.next = "VSYNC"
with m.State("VSYNC"):
with m.If(vc == vsync_end_line):
m.d.sync += vsync.eq(0)
m.next = "VBLANK"
m.next = "HSYNC"
with m.State("HSYNC"):
with m.If(hc == 590):
m.d.sync += hsync.eq(0)
m.next = "HBLANK"
# FIXME: figure out what this nonsense means and set the video output
# properly.
#reg [7:0] cos_out;
#wire [5:0] cos_g = cos_out[7:3]+6'd32;
#cos cos(vvc + {vc>>scandouble, 2'b00}, cos_out);
m.d.comb += video.eq(0);
#assign video = (cos_g >= rnd_c) ? {cos_g - rnd_c, 2'b00} : 8'd0;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment