From f4f39e42778fcc7692c24aa1afa76c21110cbd3f Mon Sep 17 00:00:00 2001 From: Krisjanis Veinbahs Date: Sun, 31 Oct 2021 23:25:47 +0200 Subject: [PATCH] More examples & monitor heartbeats --- .../domain/HardwareControlMessage.scala | 5 + .../scala/diptestbed/protocol/Codecs.scala | 34 +- .../web/actors/HardwareControlActor.scala | 59 ++- .../HardwareSerialMonitorListenerActor.scala | 4 +- .../web/controllers/HardwareController.scala | 1 - client/agent.py | 2 +- client/agent_anvyl.py | 5 +- client/agent_nrf52.py | 7 +- client/cli_util.py | 2 +- client/engine.py | 24 +- client/protocol.py | 12 +- client/s11n.py | 36 ++ client/serial_util.py | 8 +- client/serial_util_test.py | 22 + examples/anvyl-uart-remote/.gitignore | 86 ++++ .../anvyl-uart-remote/anvyl-uart-remote.xise | 367 +++++++++++++++ examples/anvyl-uart-remote/anvyl.ucf | 430 ++++++++++++++++++ examples/anvyl-uart-remote/main.v | 117 +++++ examples/anvyl-uart-remote/uart_rx.v | 149 ++++++ examples/anvyl-uart-remote/uart_tx.v | 146 ++++++ 20 files changed, 1485 insertions(+), 31 deletions(-) create mode 100644 client/serial_util_test.py create mode 100644 examples/anvyl-uart-remote/.gitignore create mode 100644 examples/anvyl-uart-remote/anvyl-uart-remote.xise create mode 100644 examples/anvyl-uart-remote/anvyl.ucf create mode 100644 examples/anvyl-uart-remote/main.v create mode 100644 examples/anvyl-uart-remote/uart_rx.v create mode 100644 examples/anvyl-uart-remote/uart_tx.v diff --git a/backend/domain/src/main/scala/diptestbed/domain/HardwareControlMessage.scala b/backend/domain/src/main/scala/diptestbed/domain/HardwareControlMessage.scala index c5738d1..ce9a38b 100644 --- a/backend/domain/src/main/scala/diptestbed/domain/HardwareControlMessage.scala +++ b/backend/domain/src/main/scala/diptestbed/domain/HardwareControlMessage.scala @@ -7,9 +7,14 @@ object HardwareControlMessage { case class UploadSoftwareRequest(softwareId: SoftwareId) extends HardwareControlMessage case class UploadSoftwareResult(error: Option[String]) extends HardwareControlMessage case class SerialMonitorRequest(serialConfig: Option[SerialConfig]) extends HardwareControlMessage + case class SerialMonitorRequestStop() extends HardwareControlMessage case class SerialMonitorResult(error: Option[String]) extends HardwareControlMessage case class SerialMonitorMessageToAgent(message: SerialMessageToAgent) extends HardwareControlMessage case class SerialMonitorMessageToClient(message: SerialMessageToClient) extends HardwareControlMessage + case class SerialMonitorListenersHeartbeatStart() extends HardwareControlMessage + case class SerialMonitorListenersHeartbeatPing() extends HardwareControlMessage + case class SerialMonitorListenersHeartbeatPong() extends HardwareControlMessage + case class SerialMonitorListenersHeartbeatFinish() extends HardwareControlMessage case class Ping() extends HardwareControlMessage val uploadUnavailableMessage: UploadSoftwareResult = diff --git a/backend/protocol/src/main/scala/diptestbed/protocol/Codecs.scala b/backend/protocol/src/main/scala/diptestbed/protocol/Codecs.scala index 87e9e1c..80a208d 100644 --- a/backend/protocol/src/main/scala/diptestbed/protocol/Codecs.scala +++ b/backend/protocol/src/main/scala/diptestbed/protocol/Codecs.scala @@ -33,12 +33,22 @@ object Codecs { private implicit val uploadSoftwareRequestCodec: Codec[UploadSoftwareRequest] = deriveCodec[UploadSoftwareRequest] private implicit val uploadSoftwareResultCodec: Codec[UploadSoftwareResult] = deriveCodec[UploadSoftwareResult] - private implicit val SerialMonitorRequestCodec: Codec[SerialMonitorRequest] = deriveCodec[SerialMonitorRequest] - private implicit val SerialMonitorResultCodec: Codec[SerialMonitorResult] = deriveCodec[SerialMonitorResult] - private implicit val SerialMonitorMessageToAgentCodec: Codec[SerialMonitorMessageToAgent] = + private implicit val serialMonitorRequestCodec: Codec[SerialMonitorRequest] = deriveCodec[SerialMonitorRequest] + private implicit val serialMonitorRequestStopCodec: Codec[SerialMonitorRequestStop] = + deriveCodec[SerialMonitorRequestStop] + private implicit val serialMonitorResultCodec: Codec[SerialMonitorResult] = deriveCodec[SerialMonitorResult] + private implicit val serialMonitorMessageToAgentCodec: Codec[SerialMonitorMessageToAgent] = deriveCodec[SerialMonitorMessageToAgent] - private implicit val SerialMonitorMessageToClientCodec: Codec[SerialMonitorMessageToClient] = + private implicit val serialMonitorMessageToClientCodec: Codec[SerialMonitorMessageToClient] = deriveCodec[SerialMonitorMessageToClient] + private implicit val serialMonitorListenersHeartbeatStartCodec: Codec[SerialMonitorListenersHeartbeatStart] = + deriveCodec[SerialMonitorListenersHeartbeatStart] + private implicit val serialMonitorListenersHeartbeatPingCodec: Codec[SerialMonitorListenersHeartbeatPing] = + deriveCodec[SerialMonitorListenersHeartbeatPing] + private implicit val serialMonitorListenersHeartbeatPongCodec: Codec[SerialMonitorListenersHeartbeatPong] = + deriveCodec[SerialMonitorListenersHeartbeatPong] + private implicit val serialMonitorListenersHeartbeatFinishCodec: Codec[SerialMonitorListenersHeartbeatFinish] = + deriveCodec[SerialMonitorListenersHeartbeatFinish] private implicit val pingCodec: Codec[Ping] = deriveCodec[Ping] @@ -47,9 +57,16 @@ object Codecs { case c: UploadSoftwareResult => NamedMessage("uploadSoftwareResult", c.asJson).asJson case c: SerialMonitorRequest => NamedMessage("serialMonitorRequest", c.asJson).asJson + case c: SerialMonitorRequestStop => NamedMessage("serialMonitorRequestStop", c.asJson).asJson case c: SerialMonitorResult => NamedMessage("serialMonitorResult", c.asJson).asJson case c: SerialMonitorMessageToAgent => NamedMessage("serialMonitorMessageToAgent", c.asJson).asJson case c: SerialMonitorMessageToClient => NamedMessage("serialMonitorMessageToClient", c.asJson).asJson + case c: SerialMonitorListenersHeartbeatStart => + NamedMessage("serialMonitorListenersHeartbeatStart", c.asJson).asJson + case c: SerialMonitorListenersHeartbeatPing => NamedMessage("serialMonitorListenersHeartbeatPing", c.asJson).asJson + case c: SerialMonitorListenersHeartbeatPong => NamedMessage("SerialMonitorListenersHeartbeatPong", c.asJson).asJson + case c: SerialMonitorListenersHeartbeatFinish => + NamedMessage("SerialMonitorListenersHeartbeatFinish", c.asJson).asJson case c: Ping => NamedMessage("ping", c.asJson).asJson } @@ -61,10 +78,19 @@ object Codecs { case "uploadSoftwareResult" => Decoder[UploadSoftwareResult].widen[HardwareControlMessage].some case "serialMonitorRequest" => Decoder[SerialMonitorRequest].widen[HardwareControlMessage].some + case "serialMonitorRequestStop" => Decoder[SerialMonitorRequestStop].widen[HardwareControlMessage].some case "serialMonitorResult" => Decoder[SerialMonitorResult].widen[HardwareControlMessage].some case "serialMonitorMessageToAgent" => Decoder[SerialMonitorMessageToAgent].widen[HardwareControlMessage].some case "serialMonitorMessageToClient" => Decoder[SerialMonitorMessageToClient].widen[HardwareControlMessage].some + case "serialMonitorListenersHeartbeatStart" => + Decoder[SerialMonitorListenersHeartbeatStart].widen[HardwareControlMessage].some + case "serialMonitorListenersHeartbeatPing" => + Decoder[SerialMonitorListenersHeartbeatPing].widen[HardwareControlMessage].some + case "serialMonitorListenersHeartbeatPong" => + Decoder[SerialMonitorListenersHeartbeatPong].widen[HardwareControlMessage].some + case "serialMonitorListenersHeartbeatFinish" => + Decoder[SerialMonitorListenersHeartbeatFinish].widen[HardwareControlMessage].some case "ping" => Decoder[Ping].widen[HardwareControlMessage].some case _ => None diff --git a/backend/web/app/diptestbed/web/actors/HardwareControlActor.scala b/backend/web/app/diptestbed/web/actors/HardwareControlActor.scala index dcd2f4d..07dc8e9 100644 --- a/backend/web/app/diptestbed/web/actors/HardwareControlActor.scala +++ b/backend/web/app/diptestbed/web/actors/HardwareControlActor.scala @@ -15,10 +15,10 @@ import diptestbed.domain.HardwareControlMessage._ import akka.util.Timeout import cats.data.EitherT import cats.implicits.toTraverseOps -import scala.annotation.unused import com.typesafe.scalalogging.LazyLogging import diptestbed.web.actors.HardwareControlState.{ConfiguringMonitor, Initial, Uploading} import diptestbed.web.actors.QueryActor.Promise +import scala.concurrent.duration.{DurationInt, FiniteDuration} sealed trait HardwareControlState {} object HardwareControlState { @@ -77,7 +77,6 @@ class HardwareControlActor( hardwareId: HardwareId, )(implicit iort: IORuntime, - @unused timeout: Timeout, ) extends Actor with LazyLogging with HardwareControlStateActions { @@ -86,6 +85,19 @@ class HardwareControlActor( val serialMonitorTopic: String = hardwareSerialMonitorTopic(hardwareId) var state: HardwareControlState = Initial + var listenerHeartbeatsReceived: Int = 0 + val listenerHeartbeatInterval: FiniteDuration = 5.seconds + val listenerHeartbeatWaitTime: FiniteDuration = 2.seconds // Should be less than the interval + + def scheduleHeartbeatTest(): IO[Unit] = { + val laterTest = IO.sleep(listenerHeartbeatInterval) >> + IO(self ! SerialMonitorListenersHeartbeatStart()) + + laterTest.start.void + } + + scheduleHeartbeatTest().unsafeRunAsync(_ => ()) + def sendToAgent(message: Control): IO[Unit] = IO(out ! message.asJson.noSpaces) def sendToRequester(requester: ActorRef, message: Control): IO[Unit] = @@ -108,13 +120,18 @@ class HardwareControlActor( def controlHandler(inquirer: Option[ActorRef], message: Control): IO[Unit] = message match { - case m: UploadSoftwareRequest => handleUploadSoftwareRequest(inquirer, m) - case m: UploadSoftwareResult => handleUploadSoftwareResult(m) - case m: SerialMonitorRequest => handleSerialMonitorRequest(inquirer, m) - case m: SerialMonitorResult => handleSerialMonitorResult(m) - case m: SerialMonitorMessageToClient => handleSerialMonitorMessageToClient(m) - case m: SerialMonitorMessageToAgent => handleSerialMonitorMessageToAgent(m) - case _: Ping => IO(()) + case m: UploadSoftwareRequest => handleUploadSoftwareRequest(inquirer, m) + case m: UploadSoftwareResult => handleUploadSoftwareResult(m) + case m: SerialMonitorRequest => handleSerialMonitorRequest(inquirer, m) + case m: SerialMonitorRequestStop => handleSerialMonitorRequestStop(m) + case m: SerialMonitorResult => handleSerialMonitorResult(m) + case m: SerialMonitorMessageToClient => handleSerialMonitorMessageToClient(m) + case m: SerialMonitorMessageToAgent => handleSerialMonitorMessageToAgent(m) + case _: SerialMonitorListenersHeartbeatStart => handleSerialMonitorListenersHeartbeatStart() + case _: SerialMonitorListenersHeartbeatPing => IO(()) + case _: SerialMonitorListenersHeartbeatPong => handleSerialMonitorListenersHeartbeatPong() + case _: SerialMonitorListenersHeartbeatFinish => handleSerialMonitorListenersHeartbeatFinish() + case _: Ping => IO(()) } def handleUploadSoftwareRequest(inquirer: Option[ActorRef], message: UploadSoftwareRequest): IO[Unit] = @@ -135,6 +152,9 @@ class HardwareControlActor( _ <- IO.whenA(isUploading)(IO(setInitialState())) } yield () + def handleSerialMonitorRequestStop(message: SerialMonitorRequestStop): IO[Unit] = + sendToAgent(message) + def handleSerialMonitorRequest(inquirer: Option[ActorRef], message: SerialMonitorRequest): IO[Unit] = for { // If available, start monitor, maybe respond eventually @@ -159,6 +179,22 @@ class HardwareControlActor( def handleSerialMonitorMessageToAgent(message: SerialMonitorMessageToAgent): IO[Unit] = sendToAgent(message) + def handleSerialMonitorListenersHeartbeatStart(): IO[Unit] = { + val startAndLaterFinish = IO { listenerHeartbeatsReceived = 0 } >> + IO(pubSubMediator ! Publish(serialMonitorTopic, SerialMonitorListenersHeartbeatPing())) >> + IO.sleep(listenerHeartbeatWaitTime) >> + IO(self ! SerialMonitorListenersHeartbeatFinish()) + + startAndLaterFinish.start.void + } + + def handleSerialMonitorListenersHeartbeatPong(): IO[Unit] = + IO { listenerHeartbeatsReceived += 1 } + + def handleSerialMonitorListenersHeartbeatFinish(): IO[Unit] = + (if (listenerHeartbeatsReceived == 0) sendToAgent(SerialMonitorRequestStop()) + else sendToAgent(SerialMonitorRequest(None))) >> + scheduleHeartbeatTest() } object HardwareControlActor extends ActorHelper { @@ -171,7 +207,6 @@ object HardwareControlActor extends ActorHelper { hardwareId: HardwareId, )(implicit iort: IORuntime, - timeout: Timeout, ): Props = Props(new HardwareControlActor(pubSubMediator, out, hardwareId)) implicit val transformer: MessageFlowTransformer[Control, String] = @@ -198,9 +233,9 @@ object HardwareControlActor extends ActorHelper { }) } yield monitorResult - def sendSerialMessageToAgent( + def sendToHardwareActor( hardwareId: HardwareId, - serialMessage: SerialMonitorMessageToAgent, + serialMessage: Control, )(implicit actorSystem: ActorSystem, t: Timeout): EitherT[IO, String, Unit] = for { hardwareRef <- resolveActorRef(userActorPath(hardwareActor(hardwareId)))(actorSystem, implicitly) diff --git a/backend/web/app/diptestbed/web/actors/HardwareSerialMonitorListenerActor.scala b/backend/web/app/diptestbed/web/actors/HardwareSerialMonitorListenerActor.scala index ffded5e..b4f807e 100644 --- a/backend/web/app/diptestbed/web/actors/HardwareSerialMonitorListenerActor.scala +++ b/backend/web/app/diptestbed/web/actors/HardwareSerialMonitorListenerActor.scala @@ -73,10 +73,12 @@ class HardwareSerialMonitorListenerActor( case serialMessage: SerialMonitorMessageToClient => val message: HardwareControlMessage = serialMessage sendToListener(message).unsafeRunAsync(_ => ()) + case _: SerialMonitorListenersHeartbeatPing => + sendToHardwareActor(hardwareId, SerialMonitorListenersHeartbeatPong()).value.unsafeRunAsync(_ => ()) case text: TextMessage => decode[HardwareControlMessage](text.data).toOption.foreach { case serialMessage: SerialMonitorMessageToAgent => - sendSerialMessageToAgent(hardwareId, serialMessage).value.unsafeRunAsync(_ => ()) + sendToHardwareActor(hardwareId, serialMessage).value.unsafeRunAsync(_ => ()) case _ => () } case _: SubscribeAck => diff --git a/backend/web/app/diptestbed/web/controllers/HardwareController.scala b/backend/web/app/diptestbed/web/controllers/HardwareController.scala index f295112..4fe9615 100644 --- a/backend/web/app/diptestbed/web/controllers/HardwareController.scala +++ b/backend/web/app/diptestbed/web/controllers/HardwareController.scala @@ -75,7 +75,6 @@ class HardwareController( def controlHardware(hardwareId: HardwareId): WebSocket = { WebSocket.accept[HardwareControlMessage, String](_ => { - implicit val timeout: Timeout = 60.seconds BetterActorFlow.actorRef( subscriber => HardwareControlActor.props(pubSubMediator, subscriber, hardwareId), maybeName = hardwareActor(hardwareId).some, diff --git a/client/agent.py b/client/agent.py index 89afb4f..351d0fb 100644 --- a/client/agent.py +++ b/client/agent.py @@ -11,7 +11,7 @@ from engine import Engine from agent_util import AgentConfig -LOGGER = log.timed_named_logger("client") +LOGGER = log.timed_named_logger("agent") PI = TypeVar('PI') PO = TypeVar('PO') diff --git a/client/agent_anvyl.py b/client/agent_anvyl.py index 7473a54..937bbc8 100644 --- a/client/agent_anvyl.py +++ b/client/agent_anvyl.py @@ -9,7 +9,8 @@ CommonIncomingMessage, \ UploadMessage, \ SerialMonitorRequest, \ - SerialMonitorMessageToAgent + SerialMonitorMessageToAgent, \ + SerialMonitorRequestStop from sh import root_relative_path, outcome_sh from agent_util import AgentConfig import log @@ -69,6 +70,8 @@ def process( return self.process_upload_message_sh(message, self.firmware_upload) elif isinstance(message, SerialMonitorRequest): return self.process_serial_monitor(self.config.device_path, message) + elif isinstance(message, SerialMonitorRequestStop): + return self.process_serial_monitor_stop() elif isinstance(message, SerialMonitorMessageToAgent): return self.process_serial_monitor_to_agent(message) else: diff --git a/client/agent_nrf52.py b/client/agent_nrf52.py index ff0edc5..c7b2d53 100644 --- a/client/agent_nrf52.py +++ b/client/agent_nrf52.py @@ -9,7 +9,8 @@ CommonIncomingMessage, \ UploadMessage, \ SerialMonitorRequest, \ - SerialMonitorMessageToAgent + SerialMonitorMessageToAgent, \ + SerialMonitorRequestStop from sh import root_relative_path, outcome_sh from agent_util import AgentConfig import log @@ -68,7 +69,9 @@ def process( if isinstance(message, UploadMessage): return self.process_upload_message_sh(message, self.firmware_upload) elif isinstance(message, SerialMonitorRequest): - return self.process_serial_monitor(self.config.device_path, message) + return self.process_serial_monitor(self.config.device, message) + elif isinstance(message, SerialMonitorRequestStop): + return self.process_serial_monitor_stop() elif isinstance(message, SerialMonitorMessageToAgent): return self.process_serial_monitor_to_agent(message) else: diff --git a/client/cli_util.py b/client/cli_util.py index c0f504a..f3e1939 100755 --- a/client/cli_util.py +++ b/client/cli_util.py @@ -36,7 +36,7 @@ ) HEARTBEAT_SECONDS_OPTION = click.option( '--heartbeat-seconds', '-r', "heartbeat_seconds", show_envvar=True, - type=int, envvar="DIP_HEARTBEAT_SECONDS", required=True, default=30, + type=int, envvar="DIP_HEARTBEAT_SECONDS", required=True, default=25, help='Regular interval in which to ping the server' ) JSON_OUTPUT_OPTION = click.option( diff --git a/client/engine.py b/client/engine.py index c4b7115..6196203 100644 --- a/client/engine.py +++ b/client/engine.py @@ -88,8 +88,12 @@ async def keep_monitoring(self): (serial, serialConfig) = self.serial received_bytes = serial.read(serialConfig.receive_size) if received_bytes is not None and len(received_bytes) > 0: - await self.monitor_to_server(received_bytes) - await asyncio.sleep(2) + # Send to server immediately, don't wait for request to finish + loop = asyncio.get_event_loop() + loop.create_task(self.monitor_to_server(received_bytes)) + # Python is trash, sleep for a bit to allow other + # async coroutines to execute + await asyncio.sleep(serialConfig.timeout) def start_monitor(self, serial: Serial, serial_config: SerialConfig): """Start serial monitoring""" @@ -106,6 +110,7 @@ def stop_monitor(self): if self.serial is not None: (serial, _) = self.serial serial.close() + self.serial = None # Socket lifecycle methods def on_start(self, socket: WebSocket): @@ -177,11 +182,20 @@ def process_serial_monitor( # Stop old monitor self.stop_monitor() - # Connect to serial device w/ the given configurations + # Define a strictly non-empty configuration if message.config is None: serial_config = SerialConfig.empty() else: serial_config = message.config + + # Avoid changes to monitoring if configuration doesn't change + if self.serial is not None: + (_, old_serial_config) = self.serial + if old_serial_config == serial_config: + LOGGER.debug("Skipping monitor request with unchanged config") + return Ok(SerialMonitorResult(None)) + + # Connect to serial device w/ the given configurations serial_result = monitor_serial(device, serial_config) if isinstance(serial_result, Err): outcome_message = f"Failed setting up monitor: {pformat(serial_result.value, indent=4)}" @@ -193,6 +207,10 @@ def process_serial_monitor( return Ok(SerialMonitorResult(None)) + def process_serial_monitor_stop(self): + """Stop serial monitoring""" + self.stop_monitor() + def process_serial_monitor_to_agent( self, message: SerialMonitorMessageToAgent diff --git a/client/protocol.py b/client/protocol.py index 52a287f..a87eec2 100644 --- a/client/protocol.py +++ b/client/protocol.py @@ -27,6 +27,12 @@ def __eq__(self, other) -> bool: return self.error == other.error +@dataclass(frozen=True, eq=False) +class SerialMonitorRequestStop: + """Message to request serial monitor stopping""" + pass + + @dataclass(frozen=True, eq=False) class SerialMonitorRequest: """Message to request serial monitor for a given microcontroller""" @@ -112,7 +118,11 @@ class PingMessage(Generic[T]): """Message for sending heartbeats to server""" -CommonIncomingMessage = Union[UploadMessage, SerialMonitorRequest, SerialMonitorMessageToAgent] +CommonIncomingMessage = Union[ + UploadMessage, + SerialMonitorRequest, + SerialMonitorRequestStop, + SerialMonitorMessageToAgent] CommonOutgoingMessage = Union[UploadResultMessage, PingMessage, SerialMonitorResult, SerialMonitorMessageToClient] MonitorListenerIncomingMessage = Union[MonitorUnavailable, SerialMonitorMessageToClient] diff --git a/client/s11n.py b/client/s11n.py index c260119..fd2a51f 100644 --- a/client/s11n.py +++ b/client/s11n.py @@ -391,6 +391,40 @@ def serial_monitor_request_decode(value: str) -> Result[protocol.SerialMonitorRe Codec(SERIAL_MONITOR_REQUEST_DECODER, SERIAL_MONITOR_REQUEST_ENCODER) +# protocol.SerialMonitorRequestStop +def serial_monitor_request_stop_encode(_: protocol.SerialMonitorRequestStop) -> str: + """Serialize SerialMonitorRequestStop to JSON""" + message = { + "command": "serialMonitorRequestStop", + "payload": {} + } + return json.dumps(message, separators=NO_WHITESPACE_SEPERATORS) + + +def serial_monitor_request_stop_decode(value: str) -> Result[protocol.SerialMonitorRequestStop, CodecParseException]: + """Un-serialize SerialMonitorRequestStop from JSON""" + json_result = json_decode(value) + if isinstance(json_result, Err): + return Err(json_result.value) + command_result = named_message_extract("serialMonitorRequestStop", json_result.value) + if isinstance(command_result, Err): + return Err(command_result.value) + result = command_result.value + + if not isinstance(result, dict): + return Err(CodecParseException("SerialMonitorRequestStop must have payload as object")) + + return Ok(protocol.SerialMonitorRequestStop()) + + +SERIAL_MONITOR_REQUEST_STOP_ENCODER: Encoder[protocol.SerialMonitorRequestStop] = \ + Encoder(serial_monitor_request_stop_encode) +SERIAL_MONITOR_REQUEST_STOP_DECODER: Decoder[protocol.SerialMonitorRequestStop] = \ + Decoder(serial_monitor_request_stop_decode) +SERIAL_MONITOR_REQUEST_STOP_CODEC: Codec[protocol.SerialMonitorRequestStop] = \ + Codec(SERIAL_MONITOR_REQUEST_STOP_DECODER, SERIAL_MONITOR_REQUEST_STOP_ENCODER) + + # protocol.SerialMonitorResult def serial_monitor_result_encode(value: protocol.SerialMonitorResult) -> str: """Serialize SerialMonitorResult to JSON""" @@ -573,11 +607,13 @@ def monitor_unavailable_decode( COMMON_INCOMING_MESSAGE_ENCODER = union_encoder({ protocol.UploadMessage: UPLOAD_MESSAGE_ENCODER, protocol.SerialMonitorRequest: SERIAL_MONITOR_REQUEST_ENCODER, + protocol.SerialMonitorRequestStop: SERIAL_MONITOR_REQUEST_STOP_ENCODER, protocol.SerialMonitorMessageToAgent: SERIAL_MONITOR_MESSAGE_TO_AGENT_ENCODER }) COMMON_INCOMING_MESSAGE_DECODER = union_decoder({ protocol.UploadMessage: UPLOAD_MESSAGE_DECODER, protocol.SerialMonitorRequest: SERIAL_MONITOR_REQUEST_DECODER, + protocol.SerialMonitorRequestStop: SERIAL_MONITOR_REQUEST_STOP_DECODER, protocol.SerialMonitorMessageToAgent: SERIAL_MONITOR_MESSAGE_TO_AGENT_DECODER }) COMMON_INCOMING_MESSAGE_CODEC = Codec( diff --git a/client/serial_util.py b/client/serial_util.py index 2268703..8ad0cff 100644 --- a/client/serial_util.py +++ b/client/serial_util.py @@ -21,9 +21,9 @@ class SerialConfig: def empty(): """Create empty serial config""" return SerialConfig( - receive_size=1, + receive_size=8, baudrate=115200, - timeout=0.5 + timeout=0.05 ) @@ -36,9 +36,9 @@ def monitor_serial( # Define serial interface serial = Serial( device, - baudrate=config.baudrate, - timeout=config.timeout + baudrate=config.baudrate ) + serial.timeout = config.timeout # Log success LOGGER.info( diff --git a/client/serial_util_test.py b/client/serial_util_test.py new file mode 100644 index 0000000..18bef25 --- /dev/null +++ b/client/serial_util_test.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Module to test serial utilities""" + +import unittest +from serial_util import SerialConfig + + +class TestSerialUtil(unittest.TestCase): + """Test suite for serial utilities""" + + def test_config_equality_check(self): + """Check that config equality works at least a little bit""" + + config1 = SerialConfig(1, 2, 3.0) + config2 = SerialConfig(1, 2, 4.0) + + self.assertTrue(config1 == config1) + self.assertFalse(config1 == config2) + + +if __name__ == '__main__': + unittest.main() diff --git a/examples/anvyl-uart-remote/.gitignore b/examples/anvyl-uart-remote/.gitignore new file mode 100644 index 0000000..a2b15cc --- /dev/null +++ b/examples/anvyl-uart-remote/.gitignore @@ -0,0 +1,86 @@ + +# Created by https://www.gitignore.io/api/xilinxise + +### XilinxISE ### +# intermediate build files +*.bgn +*.bit +*.bld +*.cmd_log +*.drc +*.ll +*.lso +*.msd +*.msk +*.ncd +*.ngc +*.ngd +*.ngr +*.pad +*.par +*.pcf +*.prj +*.ptwx +*.rbb +*.rbd +*.stx +*.syr +*.twr +*.twx +*.unroutes +*.ut +*.xpi +*.xst +*_bitgen.xwbt +*_envsettings.html +*_map.map +*_map.mrp +*_map.ngm +*_map.xrpt +*_ngdbuild.xrpt +*_pad.csv +*_pad.txt +*_par.xrpt +*_summary.html +*_summary.xml +*_usage.xml +*_xst.xrpt + +# iMPACT generated files +_impactbatch.log +impact.xsl +impact_impact.xwbt +ise_impact.cmd +webtalk_impact.xml + +# Core Generator generated files +xaw2verilog.log + +# project-wide generated files +*.gise +par_usage_statistics.html +usage_statistics_webtalk.html +webtalk.log +webtalk_pn.xml + +# generated folders +iseconfig/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ + +# End of https://www.gitignore.io/api/xilinxise +*.log +*.xmsgs +*.cmd +*.exe +*.wdb +#*.ini +#*.xise +*.tfi + + +isim/ +sch2HdlBatchFile +*.schlog diff --git a/examples/anvyl-uart-remote/anvyl-uart-remote.xise b/examples/anvyl-uart-remote/anvyl-uart-remote.xise new file mode 100644 index 0000000..fb0f658 --- /dev/null +++ b/examples/anvyl-uart-remote/anvyl-uart-remote.xise @@ -0,0 +1,367 @@ + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/examples/anvyl-uart-remote/anvyl.ucf b/examples/anvyl-uart-remote/anvyl.ucf new file mode 100644 index 0000000..a98b0ce --- /dev/null +++ b/examples/anvyl-uart-remote/anvyl.ucf @@ -0,0 +1,430 @@ +# Source: https://github.com/elomage/FPGA-resources/blob/main/ucf_templates/Anvyl.ucf + +## Anvyl board: UCF, uncomment and rename as needed +## Adapted from https://github.com/tom21091/Anvyl_Master-UCF/blob/master/Anvyl_Master.ucf + +## Clock Signal 100MHz + #NET CLK LOC = D11 | IOSTANDARD = LVCMOS33"; + NET CLK LOC = D11 | IOSTANDARD = "LVCMOS33"; + #NET "CLK" TNM_NET = sys_clk_pin; + NET "CLK" TNM_NET = sys_clk_pin; + #TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 100000 kHz; + TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 100000 kHz; + +## Switches + #NET "SW[0]" LOC = V5 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L13N_3, Sch name = SW0 + #NET "SW0" LOC = V5 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L13N_3, Sch name = SW0 + #NET "SW[1]" LOC = U4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L18P_3, Sch name = SW1 + #NET "SW1" LOC = U4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L18P_3, Sch name = SW1 + #NET "SW[2]" LOC = V3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L18N_3, Sch name = SW2 + #NET "SW2" LOC = V3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L18N_3, Sch name = SW2 + #NET "SW[3]" LOC = P4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L21P_3, Sch name = SW3 + #NET "SW3" LOC = P4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L21P_3, Sch name = SW3 + #NET "SW[4]" LOC = R4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L21N_3, Sch name = SW4 + #NET "SW4" LOC = R4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L21N_3, Sch name = SW4 + #NET "SW[5]" LOC = P6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L22P_3, Sch name = SW5 + #NET "SW5" LOC = P6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L22P_3, Sch name = SW5 + #NET "SW[6]" LOC = P5 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L22N_3, Sch name = SW6 + #NET "SW6" LOC = P5 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L22N_3, Sch name = SW6 + #NET "SW[7]" LOC = P8 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L23P_3, Sch name = SW7 + #NET "SW7" LOC = P8 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L23P_3, Sch name = SW7 + +## LEDs + #NET "LED[0]" LOC = W3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L9P_3, Sch name = LD0 + NET "LD0" LOC = W3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L9P_3, Sch name = LD0 + #NET "LED[1]" LOC = Y4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L7N_3, Sch name = LD1 + NET "LD1" LOC = Y4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L7N_3, Sch name = LD1 + #NET "LED[2]" LOC = Y1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L2N_3, Sch name = LD2 + NET "LD2" LOC = Y1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L2N_3, Sch name = LD2 + #NET "LED[3]" LOC = Y3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L8P_3, Sch name = LD3 + NET "LD3" LOC = Y3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L8P_3, Sch name = LD3 + #NET "LED[4]" LOC = AB4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L12N_3, Sch name = LD4 + NET "LD4" LOC = AB4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L12N_3, Sch name = LD4 + #NET "LED[5]" LOC = W1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L9N_3, Sch name = LD5 + NET "LD5" LOC = W1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L9N_3, Sch name = LD5 + #NET "LED[6]" LOC = AB3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L8N_3, Sch name = LD6 + NET "LD6" LOC = AB3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L8N_3, Sch name = LD6 + #NET "LED[7]" LOC = AA4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L12P_3, Sch name = LD7 + NET "LD7" LOC = AA4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L12P_3, Sch name = LD7 + +## GYR LEDs + #NET "LDT1G" LOC = T7 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L10N_3, Sch name = LDT1-G + #NET "LDT1Y" LOC = W4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L7P_3, Sch name = LDT1-Y + #NET "LDT1R" LOC = U8 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L10P_3, Sch name = LDT1-R + #NET "LDT2G" LOC = R7 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L11N_3, Sch name = LDT2-G + #NET "LDT2Y" LOC = U6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L13P_3, Sch name = LDT2-Y + #NET "LDT2R" LOC = T8 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L11P_3, Sch name = LDT2-R + + +## Buttons + #NET "BTN[0]" LOC = E6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L82P_3, Sch name = BTN0 + #NET "BTN[1]" LOC = D5 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L82N_3, Sch name = BTN1 + #NET "BTN[2]" LOC = A3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L83P_3, Sch name = BTN2 + #NET "BTN[3]" LOC = AB9 | IOSTANDARD = LVCMOS33; + +## 7 Segment Display + #NET "SEG[0]" LOC = AA21 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L63P_1, Sch name = 7SD-AA + #NET "SEG[1]" LOC = AA22 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L63N_1, Sch name = 7SD-AB + #NET "SEG[2]" LOC = Y22 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L59N_1, Sch name = 7SD-AC + #NET "SEG[3]" LOC = N15 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L60P_1, Sch name = 7SD-AD + #NET "SEG[4]" LOC = AB19 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L65P_1, Sch name = 7SD-AE + #NET "SEG[5]" LOC = P20 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L64N_1, Sch name = 7SD-AF + #NET "SEG[6]" LOC = Y21 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L59P_1, Sch name = 7SD-AG + + #NET dp LOC = P15 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L62P_1, Sch name = 7SD-DP + + #NET "AN[1]" LOC = P16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L62N_1, Sch name = 7SD-C1 + #NET "AN[0]" LOC = M17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L58N_1, Sch name = 7SD-C2 + #NET "AN[3]" LOC = N16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L60N_1, Sch name = 7SD-C3 + #NET "AN[2]" LOC = P19 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L64P_1, Sch name = 7SD-C4 + #NET "AN[5]" LOC = AA20 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L61P_1, Sch name = 7SD-C5 + #NET "AN[4]" LOC = AB21 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L61N_1, Sch name = 7SD-C6 + +## DIP Switches + #NET "DIP_A1" LOC = G6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L74P_3, Sch name = DIPA-1 + #NET "DIP_A2" LOC = G4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L74N_3, Sch name = DIPA-2 + #NET "DIP_A3" LOC = F5 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L75P_3, Sch name = DIPA-3 + #NET "DIP_A4" LOC = E5 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L75N_3, Sch name = DIPA-4 + #NET "DIP_B1" LOC = F8 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L80P_3, Sch name = DIPB-1 + #NET "DIP_B2" LOC = F7 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L80N_3, Sch name = DIPB-2 + #NET "DIP_B3" LOC = C4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L81P_3, Sch name = DIPB-3 + #NET "DIP_B4" LOC = D3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L81N_3, Sch name = DIPB-4 + +## Keypad + #NET "KYPD_COL[0]" LOC = H8 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L58P_3, Sch name = COL1 + #NET "KYPD_COL[1]" LOC = J7 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L58N_3, Sch name = COL2 + #NET "KYPD_COL[2]" LOC = K8 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L59P_3, Sch name = COL3 + #NET "KYPD_COL[3]" LOC = K7 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L59N_3, Sch name = COL4 + + #NET "KYPD_ROW[0]" LOC = E4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L60P_3, Sch name = ROW1 + #NET "KYPD_ROW[1]" LOC = F3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L60N_3, Sch name = ROW2 + #NET "KYPD_ROW[2]" LOC = G8 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L73P_3, Sch name = ROW3 + #NET "KYPD_ROW[3]" LOC = G7 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L73N_3, Sch name = ROW4 + +## OLED + #NET "OLED_SDIN" LOC = C8 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L7N_0, Sch name = OLED-SDIN + #NET "OLED_SCLK" LOC = D7 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L7P_0, Sch name = OLED-SCLK + #NET "OLED_DC" LOC = A8 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L6N_0, Sch name = OLED-DC + #NET "OLED_RES" LOC = B8 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L6P_0, Sch name = OLED-RES + #NET "OLED_VBAT" LOC = C7 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L5P_0, Sch name = OLED-VBAT + #NET "OLED_VDD" LOC = A7 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L5N_0, Sch name = OLED-VDD + +## IIC + #NET "IIC_SDA" LOC = C5 | PULLUP | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L1N_VREF_0, Sch name = SCL + #NET "IIC_SCL" LOC = A4 | PULLUP | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L2P_0, Sch name = SDA + +## AUDIO + #NET "AC_PLAYBACKDATA" LOC = A5 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L2N_0, Sch name = AC-PBDAT + #NET "AC_PLAYBACKLRC" LOC = D6 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L3P_0, Sch name = AC-PBLRC #DAC Playback sampling rate clock + #NET "AC_RECDATA" LOC = C6 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L3N_0, Sch name = AC-RECDAT + #NET "AC_RECLRC" LOC = B6 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L4P_0, Sch name = AC-RECLRC #ADC Recording sampling rate clock + #NET "AC_BCLK" LOC = B120 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L36P_GCLK15_0, Sch name = AC-BCLK + #NET "AC_CLKO" LOC = C11 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L35P_GCLK17_0, Sch name = AC-CLKO # MCLK IN FROM CODEC + #NET "AC_MUTE" LOC = A15 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L62N_VREF_0, Sch name = AC-MUTE # mute + #NET "AC_MCLK" LOC = A6 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L4N_0, Sch name = AC-MCLK + +## USB + #NET "USB1_CLK" LOC = A12 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L36N_GCLK14_0, Sch name = USBH1-SCK1 + #NET "USB1_SDI" LOC = B16 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L63P_SCP7_0, Sch name = USBH1-SDI1 + #NET "USB1_SDO" LOC = A16 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L63N_SCP6_0, Sch name = USBH1-SDO1 + #NET "USB1_SS" LOC = C17 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L64P_SCP5_0, Sch name = USBH1-SS1 + + #NET "USB2_CLK" LOC = K17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L40N_GCLK10_M1A6_1, Sch name = USBH2-CLK + #NET "USB2_DATA" LOC = L17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L40P_GCLK11_M1A5_1, Sch name = USBH2-DATA + +## RS232 + #NET "RS232_Uart_TX" LOC = T19 | IOSTANDARD = LVCMOS33"; + NET "T19" LOC = T19 | IOSTANDARD = LVCMOS33; + #NET "RS232_Uart_RX" LOC = T20 | IOSTANDARD = LVCMOS33"; + NET "T20" LOC = T20 | IOSTANDARD = LVCMOS33; + +## HDMI + #NET "HDMI_TX_P[0]" LOC = D10 | IOSTANDARD = TMDS_33; #Bank = 0, pin name = IO_L33P_0, Sch name = HDMI-TX-0 P + #NET "HDMI_TX_P[1]" LOC = C9 | IOSTANDARD = TMDS_33; #Bank = 0, pin name = IO_L8P_0, Sch name = HDMI-TX-1 P + #NET "HDMI_TX_P[2]" LOC = D9 | IOSTANDARD = TMDS_33; #Bank = 0, pin name = IO_L32P_0, Sch name = HDMI-TX-2 P + #NET "HDMI_TX_P_CLK" LOC = B10 | IOSTANDARD = TMDS_33; #Bank = 0, pin name = IO_L34P_GCLK19_0, Sch name = HDMI-TX-CLK P + + #NET "HDMI_TX_N[0]" LOC = C10 | IOSTANDARD = TMDS_33; #Bank = 0, pin name = IO_L33N_0, Sch name = HDMI-TX-0 N + #NET "HDMI_TX_N[1]" LOC = A9 | IOSTANDARD = TMDS_33; #Bank = 0, pin name = IO_L8N_VREF_0, Sch name = HDMI-TX-1 N + #NET "HDMI_TX_N[2]" LOC = D8 | IOSTANDARD = TMDS_33; #Bank = 0, pin name = IO_L32N_0, Sch name = HDMI-TX-2 N + #NET "HDMI_TX_N_CLK" LOC = A10 | IOSTANDARD = TMDS_33; #Bank = 0, pin name = IO_L34N_GCLK18_0, Sch name = HDMI-TX-CLK N + +## Ethernet + #NET "ETH_REFCLK" LOC = C12 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L37N_GCLK12_0, Sch name = ETH-REFCLK + #NET "ETH_PHY_MDC" LOC = C15 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L62P_0, Sch name = ETH-MDC + #NET "ETH_PHY_MDIO" LOC = A14 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L50N_0, Sch name = ETH-MDIO + #NET "ETH_TX_EN" LOC = D15 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L46P_0, Sch name = ETH-TXEN + #NET "ETH_TXD[0]" LOC = E10 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L38N_VREF_0, Sch name = ETH-TXD0 + #NET "ETH_TXD[1]" LOC = F10 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L38P_0, Sch name = ETH-TXD1 + #NET "ETH_CRSDV" LOC = B14 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L50P_0, Sch name = ETH-CRSDV + #NET "ETH_RXERR" LOC = A13 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L48N_0, Sch name = ETH-RXERR + #NET "ETH_RXD[0]" LOC = C13 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L48P_0, Sch name = ETH-RXD0 + #NET "ETH_RXD[1]" LOC = C14 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L46N_0, Sch name = ETH-RXD1 + +## BREADBOARD + #NET "BB1" LOC = AB20 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L65N_1, Sch name = BB1 + #NET "BB2" LOC = P17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L66P_1, Sch name = BB2 + #NET "BB3" LOC = P18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L66N_1, Sch name = BB3 + #NET "BB4" LOC = Y19 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L67P_1, Sch name = BB4 + #NET "BB5" LOC = Y20 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L67N_1, Sch name = BB5 + #NET "BB6" LOC = R15 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L68P_1, Sch name = BB6 + #NET "BB7" LOC = R16 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L68N_1, Sch name = BB7 + #NET "BB8" LOC = R17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L70P_1, Sch name = BB8 + #NET "BB9" LOC = R19 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L70N_1, Sch name = BB9 + #NET "BB10" LOC = V19 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L71P_1, Sch name = BB10 + +## JA + #NET "JA1" LOC = AA18 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L2P_CMPCLK_2, Sch name = JA1 + #NET "JA2" LOC = AA16 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L4P_2, Sch name = JA2 + #NET "JA3" LOC = Y15 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L5P_2, Sch name = JA3 + #NET "JA4" LOC = V15 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L13N_D10_2, Sch name = JA4 + #NET "JA7" LOC = AB18 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L2N_CMPMOSI_2, Sch name = JA7 + #NET "JA8" LOC = AB16 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L4N_VREF_2, Sch name = JA8 + #NET "JA9" LOC = AB15 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L5N_2, Sch name = JA9 + #NET "JA10" LOC = W15 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L14P_D11_2, Sch name = JA10 + +## JB + #NET "JB1" LOC = Y16 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L14N_D12_2, Sch name = JB1 + #NET "JB2" LOC = AB14 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L15N_2, Sch name = JB2 + #NET "JB3" LOC = Y14 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L16N_VREF_2, Sch name = JB3 + #NET "JB4" LOC = U14 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L20N_2, Sch name = JB4 + #NET "JB7" LOC = AA14 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L15P_2, Sch name = JB7 + #NET "JB8" LOC = W14 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L16P_2, Sch name = JB8 + #NET "JB9" LOC = T14 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L20P_2, Sch name = JB9 + #NET "JB10" LOC = W11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L29P_GCLK3_2, Sch name = JB10 + +## JC + #NET "JC1" LOC = Y10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L29N_GCLK2_2, Sch name = JC1 + #NET "JC2" LOC = AB12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L30N_GCLK0_USERCCLK_2, Sch name = JC2 + #NET "JC3" LOC = AB11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L31N_GCLK30_D15_2, Sch name = JC3 + #NET "JC4" LOC = AB10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L32N_GCLK28_2, Sch name = JC4 + #NET "JC7" LOC = AA12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L30P_GCLK1_D13_2, Sch name = JC7 + #NET "JC8" LOC = Y11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L31P_GCLK31_D14_2, Sch name = JC8 + #NET "JC9" LOC = AA10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L32P_GCLK29_2, Sch name = JC9 + #NET "JC10" LOC = Y13 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L41P_2, Sch name = JC10 + +## JD + #NET "JD1" LOC = AB13 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L41N_VREF_2, Sch name = JD1 + #NET "JD2" LOC = Y12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L42N_2, Sch name = JD2 + #NET "JD3" LOC = T11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L43N_2, Sch name = JD3 + #NET "JD4" LOC = W10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L44N_2, Sch name = JD4 + #NET "JD7" LOC = W12 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L42P_2, Sch name = JD7 + #NET "JD8" LOC = R11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L43P_2, Sch name = JD8 + #NET "JD9" LOC = V11 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L44P_2, Sch name = JD9 + #NET "JD10" LOC = T10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L45P_2, Sch name = JD10 + +## JE + #NET "JE1" LOC = U10 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L45N_2, Sch name = JE1 + #NET "JE2" LOC = V9 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L46N_2, Sch name = JE2 + #NET "JE3" LOC = Y8 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L47N_2, Sch name = JE3 + #NET "JE4" LOC = AA8 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L49P_D3_2, Sch name = JE4 + #NET "JE7" LOC = U9 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L46P_2, Sch name = JE7 + #NET "JE8" LOC = W9 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L47P_2, Sch name = JE8 + #NET "JE9" LOC = Y9 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L48P_D7_2, Sch name = JE9 + #NET "JE10" LOC = AB8 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L49N_D4_2, Sch name = JE10 + +## JF + #NET "JF1" LOC = V7 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L50P_2, Sch name = JF1 + #NET "JF2" LOC = W6 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L62P_D5_2, Sch name = JF2 + #NET "JF3" LOC = Y7 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L63P_2, Sch name = JF3 + #NET "JF4" LOC = AA6 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L64P_D8_2, Sch name = JF4 + #NET "JF7" LOC = W8 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L50N_2, Sch name = JF7 + #NET "JF8" LOC = Y6 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L62N_D6_2, Sch name = JF8 + #NET "JF9" LOC = AB7 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L63N_2, Sch name = JF9 + #NET "JF10" LOC = AB6 | IOSTANDARD = LVCMOS33; #Bank = 2, pin name = IO_L64N_D9_2, Sch name = JF10 + +## JG + #NET "JG1" LOC = V20 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L71N_1, Sch name = JG1 + #NET "JG2" LOC = T18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L72N_1, Sch name = JG2 + #NET "JG3" LOC = D17 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L65P_SCP3_0, Sch name = JG3 + #NET "JG4" LOC = B18 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L66P_SCP1_0, Sch name = JG4 + #NET "JG7" LOC = T17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L72P_1, Sch name = JG7 + #NET "JG8" LOC = A17 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L64N_SCP4_0, Sch name = JG8 + #NET "JG9" LOC = C16 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L65N_SCP2_0, Sch name = JG9 + #NET "JG10" LOC = A18 | IOSTANDARD = LVCMOS33; #Bank = 0, pin name = IO_L66N_SCP0_0, Sch name = JG10 + +## VGA + #NET "RED_O[0]" LOC = T3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L26P_3, Sch name = VGA-R1 + #NET "RED_O[1]" LOC = B2 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L54P_M3RESET_3, Sch name = VGA-R2 + #NET "RED_O[2]" LOC = H3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L55N_M3A14_3, Sch name = VGA-R3 + #NET "RED_O[3]" LOC = H4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L55P_M3A13_3, Sch name = VGA-R4 + + #NET "GREEN_O[0]" LOC = T4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L26P_3, Sch name = VGA-G1 + #NET "GREEN_O[1]" LOC = M6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L31P_3, Sch name = VGA-G2 + #NET "GREEN_O[2]" LOC = H6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L57P_3, Sch name = VGA-G3 + #NET "GREEN_O[3]" LOC = N6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L24N_3, Sch name = VGA-G4 + + #NET "BLUE_O[0]" LOC = M8 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L25P_3, Sch name = VGA-B1 + #NET "BLUE_O[1]" LOC = M7 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L25N_3, Sch name = VGA-B2 + #NET "BLUE_O[2]" LOC = N7 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L24P_3, Sch name = VGA-B3 + #NET "BLUE_O[3]" LOC = P7 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L23N_3, Sch name = VGA-B4 + + #NET "VSYNC_O" LOC = V18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L73N_1, Sch name = VGA-VS + #NET "HSYNC_O" LOC = V17 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L73P_1, Sch name = VGA-HS + +## Touchscreen TFT + #NET "TFT_VDDEN_O" LOC = W20 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L53P_1, Sch name = TFT-EN + #NET "TFT_B_O[0]" LOC = N22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L47N_LDC_M1DQ1_1, Sch name = TFT-B0 + #NET "TFT_B_O[1]" LOC = P22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L48N_M1DQ9_1, Sch name = TFT-B1 + #NET "TFT_B_O[2]" LOC = P21 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L48P_HDC_M1DQ8_1, Sch name = TFT-B2 + #NET "TFT_B_O[3]" LOC = R22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L49N_M1DQ11_1, Sch name = TFT-B3 + #NET "TFT_B_O[4]" LOC = T22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L50N_M1UDQSN_1, Sch name = TFT-B4 + #NET "TFT_B_O[5]" LOC = T21 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L50P_M1UDQS_1, Sch name = TFT-B5 + #NET "TFT_B_O[6]" LOC = U22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L51N_M1DQ13_1, Sch name = TFT-B6 + #NET "TFT_B_O[7]" LOC = V22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L52N_M1DQ15_1, Sch name = TFT-B7 + #NET "TFT_CLK_O" LOC = L20 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L43P_GCLK5_M1DQ4_1, Sch name = TFT-CLK + #NET "TFT_DE_O" LOC = W22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L53N_VREF_1, Sch name = TFT-DE + #NET "TFT_DISP_O" LOC = V21 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L52P_M1DQ14_1, Sch name = TFT-DISP + #NET "TFT_G_O[0]" LOC = C22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L35N_A10_M1A2_1, Sch name = TFT-G0 + #NET "TFT_G_O[1]" LOC = B22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L37N_A6_M1A1_1, Sch name = TFT-G1 + #NET "TFT_G_O[2]" LOC = B21 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L37P_A7_M1A0_1, Sch name = TFT-G2 + #NET "TFT_G_O[3]" LOC = H22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L34N_A12_M1BA2_1, Sch name = TFT-G3 + #NET "TFT_G_O[4]" LOC = K22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L44N_A2_M1DQ7_1, Sch name = TFT-G4 + #NET "TFT_G_O[5]" LOC = L22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L43N_GCLK4_M1DQ5_1, Sch name = TFT-G5 + #NET "TFT_G_O[6]" LOC = M22 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L45N_A0_M1LDQSN_1, Sch name = TFT-G6 + #NET "TFT_G_O[7]" LOC = M21 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L45P_A1_M1LDQS_1, Sch name = TFT-G7 + #NET "TFT_BKLT_O" LOC = M16 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L58P_1, Sch name = TFT-LED + #NET "TFT_R_O[0]" LOC = R20 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L49P_M1DQ10_1, Sch name = TFT-R0 + #NET "TFT_R_O[1]" LOC = N19 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L46P_FCS_B_M1DQ2_1, Sch name = TFT-R1 + #NET "TFT_R_O[2]" LOC = K19 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L36N_A8_M1BA1_1, Sch name = TFT-R2 + #NET "TFT_R_O[3]" LOC = K20 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L42N_GCLK6_TRDY1_M1LDM_1, Sch name = TFT-R3 + #NET "TFT_R_O[4]" LOC = K18 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L36P_A9_M1BA0_1, Sch name = TFT-R4 + #NET "TFT_R_O[5]" LOC = J19 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L38N_A4_M1CLKN_1, Sch name = TFT-R5 + #NET "TFT_R_O[6]" LOC = J17 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L38P_A5_M1CLK_1, Sch name = TFT-R6 + #NET "TFT_R_O[7]" LOC = C20 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L35P_A11_M1A7_1, Sch name = TFT-R7 + #NET "TP_BUSY_I" LOC = M19 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L41N_GCLK8_M1CASN_1, Sch name = TFT-BUSY + #NET "TP_CS_O" LOC = M20 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L46N_FOE_B_M1DQ3_1, Sch name = TFT-CS + #NET "TP_DCLK_O" LOC = K21 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L44P_A3_M1DQ6_1, Sch name = TFT-DCLK + #NET "TP_DIN_O" LOC = U20 | IOSTANDARD = LVCMOS33 | OUT_TERM = UNTUNED_75; #Bank = 1, pin name = IO_L51P_M1DQ12_1, Sch name = TFT-DIN + #NET "TP_DOUT_I" LOC = M18 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L41P_GCLK9_IRDY1_M1RASN_1, Sch name = TFT-DOUT + #NET "TP_PENIRQ_I" LOC = N20 | IOSTANDARD = LVCMOS33; #Bank = 1, pin name = IO_L47P_FWE_B_M1DQ0_1, Sch name = TFT-PEN + + #INST "TFT_R_O[7]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_R_O[0]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_R_O[1]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_R_O[2]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_R_O[3]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_R_O[4]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_R_O[5]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_R_O[6]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_B_O[0]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_B_O[1]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_B_O[2]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_B_O[3]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_B_O[4]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_B_O[5]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_B_O[6]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_B_O[7]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_CLK_O" TNM = TFT_PIXEL_BUS"; + #INST "TFT_DE_O" TNM = TFT_PIXEL_BUS"; + #INST "TFT_G_O[0]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_G_O[1]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_G_O[2]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_G_O[3]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_G_O[4]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_G_O[5]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_G_O[6]" TNM = TFT_PIXEL_BUS"; + #INST "TFT_G_O[7]" TNM = TFT_PIXEL_BUS"; + #TIMEGRP "TFT_PIXEL_BUS" OFFSET = OUT AFTER "CLK_I" REFERENCE_PIN "TFT_CLK_O"; + +## SRAM + #NET "Memory_address[0]" LOC = F22 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L29N_A22_M1A14_1, Sch name = SRAM-A0 + #NET "Memory_address[1]" LOC = F21 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L29P_A23_M1A13_1, Sch name = SRAM-A1 + #NET "Memory_address[2]" LOC = E22 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L31N_A18_M1A12_1, Sch name = SRAM-A2 + #NET "Memory_address[3]" LOC = D22 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L33N_A14_M1A4_1, Sch name = SRAM-A3 + #NET "Memory_address[4]" LOC = D21 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L33P_A15_M1A10_1, Sch name = SRAM-A4 + #NET "Memory_address[5]" LOC = D19 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L11P_1, Sch name = SRAM-A5 + #NET "Memory_address[6]" LOC = D20 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L11N_1, Sch name = SRAM-A6 + #NET "Memory_address[7]" LOC = E20 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L31P_A19_M1CKE_1, Sch name = SRAM-A7 + #NET "Memory_address[8]" LOC = G17 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L13P_1, Sch name = SRAM-A8 + #NET "Memory_address[9]" LOC = H18 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L17N_1, Sch name = SRAM-A9 + #NET "Memory_address[10]" LOC = H13 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L21P_1, Sch name = SRAM-A10 + #NET "Memory_address[11]" LOC = H12 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L219P_1, Sch name = SRAM-A11 + #NET "Memory_address[12]" LOC = K16 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L28N_VREF_1, Sch name = SRAM-A12 + #NET "Memory_address[13]" LOC = L15 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L28P_1, Sch name = SRAM-A13 + #NET "Memory_address[14]" LOC = G15 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L10P_1, Sch name = SRAM-A14 + #NET "Memory_address[15]" LOC = J16 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L20P_1, Sch name = SRAM-A15 + #NET "Memory_address[16]" LOC = H17 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L17P_1, Sch name = SRAM-A16 + #NET "Memory_address[17]" LOC = H16 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L20N_1, Sch name = SRAM-A17 + #NET "Memory_address[18]" LOC = G16 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L10N_1, Sch name = SRAM-A18 + + #NET "Memory_data[0]" LOC = H21 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L34P_A13_M1WE_1, Sch name = SRAM-DQ0 + #NET "Memory_data[1]" LOC = A20 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L16N_1, Sch name = SRAM-DQ1 + #NET "Memory_data[2]" LOC = A21 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L14N_1, Sch name = SRAM-DQ2 + #NET "Memory_data[3]" LOC = A19 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L16P_1, Sch name = SRAM-DQ3 + #NET "Memory_data[4]" LOC = B20 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L14P_1, Sch name = SRAM-DQ4 + #NET "Memory_data[5]" LOC = C18 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L12P_1, Sch name = SRAM-DQ5 + #NET "Memory_data[6]" LOC = C19 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L12N_1, Sch name = SRAM-DQ6 + #NET "Memory_data[7]" LOC = F15 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L1P_A25_1, Sch name = SRAM-DQ7 + #NET "Memory_data[8]" LOC = F18 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L15N_1, Sch name = SRAM-DQ8 + #NET "Memory_data[9]" LOC = F17 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L15P_1, Sch name = SRAM-DQ9 + #NET "Memory_data[10]" LOC = F14 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L9N_1, Sch name = SRAM-DQ10 + #NET "Memory_data[11]" LOC = F13 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L9P, Sch name = SRAM-DQ11 + #NET "Memory_data[12]" LOC = H14 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L21N_1, Sch name = SRAM-DQ12 + #NET "Memory_data[13]" LOC = H19 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L30P_A21_M1RESET_1, Sch name = SRAM-DQ13 + #NET "Memory_data[14]" LOC = H20 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L30N_A20_M1A11_1, Sch name = SRAM-DQ14 + #NET "Memory_data[15]" LOC = G20 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L32P_A17_M1A8_1, Sch name = SRAM-DQ15 + + #NET "SRAM_CS1" LOC = G22 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L32N_A16_M1A9_1, Sch name = SRAM-CS1 + #NET "SRAM_CS2" LOC = G13 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L19N_1, Sch name = SRAM-CS2 + + #NET "SRAM_OE" LOC = F19 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L18P_1, Sch name = SRAM-OE + #NET "SRAM_WE" LOC = F16 | IOSTANDARD = LVCMOS33"; #Bank = 1, pin name = IO_L1N_A24_VREF_1, Sch name = SRAM-WE + + #NET "SRAM_UPPER_B" LOC = F20 | IOSTANDARD = LVCMOS33" | DRIVE = 2 | PULLDOWN; #Bank = 1, pin name = IO_L18N_1, Sch name = SRAM-UB + #NET "SRAM_LOWER_B" LOC = G19 | IOSTANDARD = LVCMOS33" | DRIVE = 2 | PULLDOWN; #Bank = 1, pin name = IO_L13N_1, Sch name = SRAM-LB + + +## DDR2 + #NET "DDR_DATA[0]" LOC = N3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L37P_M3DQ0_3, Sch name = DDR-DQ0 + #NET "DDR_DATA[1]" LOC = N1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L37N_M3DQ1_3, Sch name = DDR-DQ1 + #NET "DDR_DATA[2]" LOC = M2 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L38P_M3DQ2_3, Sch name = DDR-DQ2 + #NET "DDR_DATA[3]" LOC = M1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L38N_M3DQ3_3, Sch name = DDR-DQ3 + #NET "DDR_DATA[4]" LOC = J3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L41P_GCLK27_M3DQ4_3, name = DDR-DQ4 + #NET "DDR_DATA[5]" LOC = J1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L41N_GCLK26_M3DQ5_3, name = DDR-DQ5 + #NET "DDR_DATA[6]" LOC = K2 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L40P_M3DQ6_3, Sch name = DDR-DQ6 + #NET "DDR_DATA[7]" LOC = K1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L40N_M3DQ7_3, Sch name = DDR-DQ7 + #NET "DDR_DATA[8]" LOC = P2 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L36P_M3DQ8_3, Sch name = DDR-DQ8 + #NET "DDR_DATA[9]" LOC = P1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L36N_M3DQ9_3, Sch name = DDR-DQ9 + #NET "DDR_DATA[10]" LOC = R3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L35P_M3DQ10_3, Sch name = DDR-DQ10 + #NET "DDR_DATA[11]" LOC = R1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L35N_M3DQ11_3, Sch name = DDR-DQ11 + #NET "DDR_DATA[12]" LOC = U3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L33P_M3DQ12_3, Sch name = DDR-DQ12 + #NET "DDR_DATA[13]" LOC = U1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L33N_M3DQ13_3, Sch name = DDR-DQ13 + #NET "DDR_DATA[14]" LOC = V2 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L32P_M3DQ14_3, Sch name = DDR-DQ14 + #NET "DDR_DATA[15]" LOC = V1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L32N_M3DQ15_3, Sch name = DDR-DQ15 + + #NET "DDR_ADDR[0]" LOC = M5 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L47P_M3A0_3, Sch name = DDR-A0 + #NET "DDR_ADDR[1]" LOC = L4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L47N_M3A1_3, Sch name = DDR-A1 + #NET "DDR_ADDR[2]" LOC = K3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L49N_M3A2_3, Sch name = DDR-A2 + #NET "DDR_ADDR[3]" LOC = M4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L45P_M3A3_3, Sch name = DDR-A3 + #NET "DDR_ADDR[4]" LOC = K5 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L51N_M3A4_3, Sch name = DDR-A4 + #NET "DDR_ADDR[5]" LOC = G3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L44P_GCLK21_M3A5_3, Sch name = DDR-A5 + #NET "DDR_ADDR[6]" LOC = G1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L44N_GCLK20_M3A6_3, Sch name = DDR-A6 + #NET "DDR_ADDR[7]" LOC = K4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L49P_M3A7_3, Sch name = DDR-A7 + #NET "DDR_ADDR[8]" LOC = C3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L52P_M3A8_3, Sch name = DDR-A8 + #NET "DDR_ADDR[9]" LOC = C1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L52N_M3A9_3, Sch name = DDR-A9 + #NET "DDR_ADDR[10]" LOC = K6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L51P_M3A10_3, Sch name = DDR-A10 + #NET "DDR_ADDR[11]" LOC = B1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L54N_M3A11_3, Sch name = DDR-A11 + #NET "DDR_ADDR[12]" LOC = J4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L53N_M3A12_3, Sch name = DDR-A12 + + #NET "DDR_CLK_EN" LOC = J6 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L53P_M3CKE_3, Sch name = DDR-CKE #CLK ENABLE + #NET "DDR_CLK_P" LOC = F2 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L45N_M3CLK_3, Sch name = DDR-CK P #+CLK + #NET "DDR_CLK_N" LOC = F1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L46P_M3CLKN_3, Sch name = DDR-CK N #-CLK + + #NET "DDR_BA[0]" LOC = E3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L48P_M3BA0_3, Sch name = DDR-BA0 #BANK ADDRESS INPUTS + #NET "DDR_BA[1]" LOC = E1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L48N_M3BA1_3, Sch name = DDR-BA1 + #NET "DDR_BA2[2]" LOC = D1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L50N_M3BA2_3, Sch name = DDR-BA2 + + #NET "DDR_UDM" LOC = H2 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L42P_GCLK25_TRDY2_M3UDM_3, Sch name = DDR-UDM #DQ WRITE MASK ENABLE INPUTS + #NET "DDR_LDM" LOC = H1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L42N_GCLK24_M3LDM_3, Sch name = DDR-LDM + + #NET "DDR_ODT LOC = M3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L45N_M3ODT_3, Sch name = DDR-ODT #ON-DIE TERMINATION + + #NET "DDR_UDQS_P LOC = T2 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L34P_M3UDQS_3, Sch name = DDR-UDQS P #DATA STROBE INPUTS/OUTPUTS + #NET "DDR_UDQS_N LOC = T1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L34N_M3UDQSN_3, Sch name = DDR-UDQS N + #NET "DDR_LDQS_P LOC = L3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L39P_M3LDQS_3, Sch name = DDR-LDQS P + #NET "DDR_LDQS_N LOC = L1 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L39N_M3LDQSN_3, Sch name = DDR-LDQS N + + #NET "DDR_RAS LOC = N4 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L43P_GCLK23_M3RASN_3, Sch name = DDR-RAS #ROW ADDRESS STROBE INPUT + #NET "DDR_CAS LOC = P3 | IOSTANDARD = LVCMOS18; #Bank = 3, pin name = IO_L43N_GCLK22_IRDY2_M3CASN_3, Sch name = DDR-CAS #COLUMN ADDRESS STROBE INPUT + \ No newline at end of file diff --git a/examples/anvyl-uart-remote/main.v b/examples/anvyl-uart-remote/main.v new file mode 100644 index 0000000..0e3df55 --- /dev/null +++ b/examples/anvyl-uart-remote/main.v @@ -0,0 +1,117 @@ +// Import NANDLAND's UART Verilog +include "uart_rx.v"; +include "uart_tx.v"; + +// Define a UART reader/transmitter FPGA program +module main( + // Clock pin + input CLK, + + // UART RX/TX pins + input T19, + output T20, + + // Physical GPIO: LEDs + output LD0, + output LD1, + output LD2, + output LD3, + output LD4, + output LD5, + output LD6, + output LD7 +); + // Instantiate NANDLAND's UART RX instance + wire [7:0] rx_data; + reg [7:0] rx_data_reg; + reg [7:0] rx_data_reg_prim; + wire rx_ready; + + uart_rx uart_rx_instance ( + .i_Clock(CLK), + .i_Rx_Serial(T19), + .o_Rx_DV(rx_ready), + .o_Rx_Byte(rx_data) + ); + + // Print out state of received data + assign LD0 = rx_data_reg[0]; + assign LD1 = rx_data_reg[1]; + assign LD2 = rx_data_reg[2]; + assign LD3 = rx_data_reg[3]; + assign LD4 = rx_data_reg[4]; + assign LD5 = rx_data_reg[5]; + assign LD6 = rx_data_reg[6]; + assign LD7 = rx_data_reg[7]; + + // Copy the data when it's been read + always @(posedge CLK) + begin + if (rx_ready == 1) begin + rx_data_reg <= rx_data; + rx_data_reg_prim <= rx_data + 1; + end + end + + // Instantiate NANDLAND's UART TX instance + wire tx_ready; + wire [7:0] tx_data; + wire tx_done; + + uart_tx uart_tx_instance ( + .i_Clock(CLK), + .i_Tx_DV(tx_ready), + .i_Tx_Byte(tx_data), + .o_Tx_Active(), + .o_Tx_Serial(T20), + .o_Tx_Done(tx_done) + ); + + // Make tx_ready writeable + reg r_tx_ready = 0; + assign tx_ready = r_tx_ready; + + // Assign rx_data + 1 to tx_data + assign tx_data[0] = rx_data_reg_prim[0]; + assign tx_data[1] = rx_data_reg_prim[1]; + assign tx_data[2] = rx_data_reg_prim[2]; + assign tx_data[3] = rx_data_reg_prim[3]; + assign tx_data[4] = rx_data_reg_prim[4]; + assign tx_data[5] = rx_data_reg_prim[5]; + assign tx_data[6] = rx_data_reg_prim[6]; + assign tx_data[7] = rx_data_reg_prim[7]; + + // Make a CLK-based sleep counter for printing stuff + reg [31:0] r_ticks = 0; + + // Every N ticks print data and reset counter + // 100000000 = 1 second + // 100000000 = 1 second + // 30000000 = 0.3 second + // 10000000 = 0.1 second + // 5000000 = 0.05 second + // + // Currently 0.05 seconds is the serial port refresh rate + // although every read is 8 bytes, this program only writes + // 1 byte per the refresh rate i.e. you can go ~8 times faster + // i.e. somewhere around 0.0625 seconds and thereby + // the agent will read 8 bytes every 0.05 seconds + // + // N.B. If you write too fast, then the agent won't catch up + // and eventually will lag extremely behind and you'll be sad + parameter sleep = 32'd30000000; + always @(posedge CLK) + begin + if (r_ticks < sleep) begin + r_ticks = r_ticks + 1; + end + else if (r_ticks == sleep) begin + r_tx_ready = 1; + r_ticks = r_ticks + 1; + end + else begin + r_tx_ready = 0; + r_ticks = 0; + end + end +endmodule diff --git a/examples/anvyl-uart-remote/uart_rx.v b/examples/anvyl-uart-remote/uart_rx.v new file mode 100644 index 0000000..9259e87 --- /dev/null +++ b/examples/anvyl-uart-remote/uart_rx.v @@ -0,0 +1,149 @@ +// Source: https://www.nandland.com/vhdl/modules/module-uart-serial-port-rs232.html +// Note: Clock counter expanded to 32 bits because of external clock being 100MHz not 10MHz + +////////////////////////////////////////////////////////////////////// +// File Downloaded from http://www.nandland.com +////////////////////////////////////////////////////////////////////// +// This file contains the UART Receiver. This receiver is able to +// receive 8 bits of serial data, one start bit, one stop bit, +// and no parity bit. When receive is complete o_rx_dv will be +// driven high for one clock cycle. +// +// Set Parameter CLKS_PER_BIT as follows: +// CLKS_PER_BIT = (Frequency of i_Clock)/(Frequency of UART) +// Example: 10 MHz Clock, 115200 baud UART +// (10000000)/(115200) = 87 + +module uart_rx #(parameter CLKS_PER_BIT = 870)( + input i_Clock, + input i_Rx_Serial, + output o_Rx_DV, + output [7:0] o_Rx_Byte +); + + parameter s_IDLE = 3'b000; + parameter s_RX_START_BIT = 3'b001; + parameter s_RX_DATA_BITS = 3'b010; + parameter s_RX_STOP_BIT = 3'b011; + parameter s_CLEANUP = 3'b100; + + reg r_Rx_Data_R = 1'b1; + reg r_Rx_Data = 1'b1; + + reg [31:0] r_Clock_Count = 0; + reg [2:0] r_Bit_Index = 0; //8 bits total + reg [7:0] r_Rx_Byte = 0; + reg r_Rx_DV = 0; + reg [2:0] r_SM_Main = 0; + + // Purpose: Double-register the incoming data. + // This allows it to be used in the UART RX Clock Domain. + // (It removes problems caused by metastability) + always @(posedge i_Clock) + begin + r_Rx_Data_R <= i_Rx_Serial; + r_Rx_Data <= r_Rx_Data_R; + end + + + // Purpose: Control RX state machine + always @(posedge i_Clock) + begin + + case (r_SM_Main) + s_IDLE : + begin + r_Rx_DV <= 1'b0; + r_Clock_Count <= 0; + r_Bit_Index <= 0; + + if (r_Rx_Data == 1'b0) // Start bit detected + r_SM_Main <= s_RX_START_BIT; + else + r_SM_Main <= s_IDLE; + end + + // Check middle of start bit to make sure it's still low + s_RX_START_BIT : + begin + if (r_Clock_Count == (CLKS_PER_BIT-1)/2) + begin + if (r_Rx_Data == 1'b0) + begin + r_Clock_Count <= 0; // reset counter, found the middle + r_SM_Main <= s_RX_DATA_BITS; + end + else + r_SM_Main <= s_IDLE; + end + else + begin + r_Clock_Count <= r_Clock_Count + 1; + r_SM_Main <= s_RX_START_BIT; + end + end // case: s_RX_START_BIT + + + // Wait CLKS_PER_BIT-1 clock cycles to sample serial data + s_RX_DATA_BITS : + begin + if (r_Clock_Count < CLKS_PER_BIT-1) + begin + r_Clock_Count <= r_Clock_Count + 1; + r_SM_Main <= s_RX_DATA_BITS; + end + else + begin + r_Clock_Count <= 0; + r_Rx_Byte[r_Bit_Index] <= r_Rx_Data; + + // Check if we have received all bits + if (r_Bit_Index < 7) + begin + r_Bit_Index <= r_Bit_Index + 1; + r_SM_Main <= s_RX_DATA_BITS; + end + else + begin + r_Bit_Index <= 0; + r_SM_Main <= s_RX_STOP_BIT; + end + end + end // case: s_RX_DATA_BITS + + + // Receive Stop bit. Stop bit = 1 + s_RX_STOP_BIT : + begin + // Wait CLKS_PER_BIT-1 clock cycles for Stop bit to finish + if (r_Clock_Count < CLKS_PER_BIT-1) + begin + r_Clock_Count <= r_Clock_Count + 1; + r_SM_Main <= s_RX_STOP_BIT; + end + else + begin + r_Rx_DV <= 1'b1; + r_Clock_Count <= 0; + r_SM_Main <= s_CLEANUP; + end + end // case: s_RX_STOP_BIT + + + // Stay here 1 clock + s_CLEANUP : + begin + r_SM_Main <= s_IDLE; + r_Rx_DV <= 1'b0; + end + + + default : + r_SM_Main <= s_IDLE; + + endcase + end + + assign o_Rx_DV = r_Rx_DV; + assign o_Rx_Byte = r_Rx_Byte; +endmodule diff --git a/examples/anvyl-uart-remote/uart_tx.v b/examples/anvyl-uart-remote/uart_tx.v new file mode 100644 index 0000000..e0b87da --- /dev/null +++ b/examples/anvyl-uart-remote/uart_tx.v @@ -0,0 +1,146 @@ +// Source: https://www.nandland.com/vhdl/modules/module-uart-serial-port-rs232.html +// Note: Clock counter expanded to 32 bits because of external clock being 100MHz not 10MHz + +////////////////////////////////////////////////////////////////////// +// File Downloaded from http://www.nandland.com +////////////////////////////////////////////////////////////////////// +// This file contains the UART Transmitter. This transmitter is able +// to transmit 8 bits of serial data, one start bit, one stop bit, +// and no parity bit. When transmit is complete o_Tx_done will be +// driven high for one clock cycle. +// +// Set Parameter CLKS_PER_BIT as follows: +// CLKS_PER_BIT = (Frequency of i_Clock)/(Frequency of UART) +// Example: 10 MHz Clock, 115200 baud UART +// (10000000)/(115200) = 87 + +module uart_tx #(parameter CLKS_PER_BIT = 870) ( + input i_Clock, + input i_Tx_DV, + input [7:0] i_Tx_Byte, + output o_Tx_Active, + output reg o_Tx_Serial, + output o_Tx_Done +); + + parameter s_IDLE = 3'b000; + parameter s_TX_START_BIT = 3'b001; + parameter s_TX_DATA_BITS = 3'b010; + parameter s_TX_STOP_BIT = 3'b011; + parameter s_CLEANUP = 3'b100; + + reg [2:0] r_SM_Main = 0; + reg [31:0] r_Clock_Count = 0; + reg [2:0] r_Bit_Index = 0; + reg [7:0] r_Tx_Data = 0; + reg r_Tx_Done = 0; + reg r_Tx_Active = 0; + + always @(posedge i_Clock) + begin + + case (r_SM_Main) + s_IDLE : + begin + o_Tx_Serial <= 1'b1; // Drive Line High for Idle + r_Tx_Done <= 1'b0; + r_Clock_Count <= 0; + r_Bit_Index <= 0; + + if (i_Tx_DV == 1'b1) + begin + r_Tx_Active <= 1'b1; + r_Tx_Data <= i_Tx_Byte; + r_SM_Main <= s_TX_START_BIT; + end + else + r_SM_Main <= s_IDLE; + end // case: s_IDLE + + + // Send out Start Bit. Start bit = 0 + s_TX_START_BIT : + begin + o_Tx_Serial <= 1'b0; + + // Wait CLKS_PER_BIT-1 clock cycles for start bit to finish + if (r_Clock_Count < CLKS_PER_BIT-1) + begin + r_Clock_Count <= r_Clock_Count + 1; + r_SM_Main <= s_TX_START_BIT; + end + else + begin + r_Clock_Count <= 0; + r_SM_Main <= s_TX_DATA_BITS; + end + end // case: s_TX_START_BIT + + + // Wait CLKS_PER_BIT-1 clock cycles for data bits to finish + s_TX_DATA_BITS : + begin + o_Tx_Serial <= r_Tx_Data[r_Bit_Index]; + + if (r_Clock_Count < CLKS_PER_BIT-1) + begin + r_Clock_Count <= r_Clock_Count + 1; + r_SM_Main <= s_TX_DATA_BITS; + end + else + begin + r_Clock_Count <= 0; + + // Check if we have sent out all bits + if (r_Bit_Index < 7) + begin + r_Bit_Index <= r_Bit_Index + 1; + r_SM_Main <= s_TX_DATA_BITS; + end + else + begin + r_Bit_Index <= 0; + r_SM_Main <= s_TX_STOP_BIT; + end + end + end // case: s_TX_DATA_BITS + + + // Send out Stop bit. Stop bit = 1 + s_TX_STOP_BIT : + begin + o_Tx_Serial <= 1'b1; + + // Wait CLKS_PER_BIT-1 clock cycles for Stop bit to finish + if (r_Clock_Count < CLKS_PER_BIT-1) + begin + r_Clock_Count <= r_Clock_Count + 1; + r_SM_Main <= s_TX_STOP_BIT; + end + else + begin + r_Tx_Done <= 1'b1; + r_Clock_Count <= 0; + r_SM_Main <= s_CLEANUP; + r_Tx_Active <= 1'b0; + end + end // case: s_Tx_STOP_BIT + + + // Stay here 1 clock + s_CLEANUP : + begin + r_Tx_Done <= 1'b1; + r_SM_Main <= s_IDLE; + end + + + default : + r_SM_Main <= s_IDLE; + + endcase + end + + assign o_Tx_Active = r_Tx_Active; + assign o_Tx_Done = r_Tx_Done; +endmodule