
<?xml 
version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="https://63f09.systella.fr/spip.php?page=backend.xslt" ?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:atom="http://www.w3.org/2005/Atom"
>

<channel xml:lang="en">
	<title>63F09</title>
	<link>https://63F09.systella.fr/</link>
	<description></description>
	<language>en</language>
	<generator>SPIP - www.spip.net</generator>
	<atom:link href="https://63f09.systella.fr/spip.php?id_rubrique=5&amp;page=backend" rel="self" type="application/rss+xml" />

	<image>
		<title>63F09</title>
		<url>https://63f09.systella.fr/local/cache-vignettes/L110xH56/kl_motorola_mc6809-0d844.jpg?1788338251</url>
		<link>https://63F09.systella.fr/</link>
		<height>56</height>
		<width>110</width>
	</image>



<item xml:lang="en">
		<title>BAC 63F81</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/bac-63f81</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/bac-63f81</guid>
		<dc:date>2024-08-23T17:22:19Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>
&lt;p&gt;The shared bus arbiter 63F81 &lt;br class='autobr' /&gt;
On a multi-core 63F09 build, all cores share a single external bus interface &#8212; one set of address, data, and control pins. 63F81.vhd instantiates one DMC_63F41 (with its own L1 cache, see the companion document) per core, and arbitrates which core's signals actually drive that shared interface at any given moment. &lt;br class='autobr' /&gt;
One master at a time, chosen by a sticky round robin &lt;br class='autobr' /&gt;
The arbiter tracks a single integer, SIGNAL_LAST_ACTIVE_CPU &#8212; the index of the core&#160;(&#8230;)&lt;/p&gt;


-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;h2 class=&#034;spip&#034;&gt;The shared bus arbiter 63F81&lt;/h2&gt;
&lt;p&gt;On a multi-core 63F09 build, all cores share a single external bus interface &#8212; one set of address, data, and control pins. &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;63F81.vhd&lt;/code&gt; instantiates one &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;DMC_63F41&lt;/code&gt; (with its own L1 cache, see the companion document) per core, and arbitrates which core's signals actually drive that shared interface at any given moment.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;One master at a time, chosen by a sticky round robin&lt;/h2&gt;
&lt;p&gt;The arbiter tracks a single integer, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;SIGNAL_LAST_ACTIVE_CPU&lt;/code&gt; &#8212; the index of the core currently granted the bus. It is recomputed by a purely combinational process, sensitive only to the per-core &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_REQUEST&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;LOCK_REQUEST&lt;/code&gt; vectors:&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre class='spip_code spip_code_block' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;for i in 0 to NCPUS loop CURRENT_CPU := (SIGNAL_LAST_ACTIVE_CPU + i) mod NCPUS; if ((BUS_REQUEST(CURRENT_CPU)='1') or (LOCK_REQUEST(CURRENT_CPU)='1')) and (REG_CONFIGURATION(CURRENT_CPU)='1') then exit; end if; end loop; SIGNAL_LAST_ACTIVE_CPU &lt;= CURRENT_CPU;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The search always starts from the &lt;strong&gt;current&lt;/strong&gt; master (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;i=0&lt;/code&gt; maps back to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;SIGNAL_LAST_ACTIVE_CPU&lt;/code&gt; itself). As long as that core keeps asserting &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_REQUEST&lt;/code&gt; or &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;LOCK_REQUEST&lt;/code&gt; and remains enabled in &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;REG_CONFIGURATION&lt;/code&gt;, the loop exits immediately on its very first iteration and &lt;strong&gt;the same core keeps the bus&lt;/strong&gt; &#8212; there is no forced, time-sliced rotation while a master keeps asking. Only once the current master's own request drops (or it is disabled) does the search continue forward, round-robin, to the next requesting, enabled core. If nothing at all is requesting, the loop runs to completion (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;i=NCPUS&lt;/code&gt; wraps back to the current master) and the arbiter simply parks on the same core by default.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Grants are a strict one-hot&lt;/h2&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_GRANTED&lt;/code&gt;, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;LOCK_GRANTED&lt;/code&gt; and &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;REG_CURRENT_CPU&lt;/code&gt; are all derived from &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;SIGNAL_LAST_ACTIVE_CPU&lt;/code&gt; alone, in a second, equally combinational process: every entry is cleared, then exactly the one at index &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;SIGNAL_LAST_ACTIVE_CPU&lt;/code&gt; is set. Exactly one core ever holds the bus (and the lock) at a time; every other core's &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_GRANTED(i)&lt;/code&gt; reads &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'0'&lt;/code&gt; and its request simply waits for its turn.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Only the master sees the real external signals&lt;/h2&gt;
&lt;p&gt;The same process default-initializes every core's &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_MRDY&lt;/code&gt;, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_DMA_BREQ_n&lt;/code&gt;, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_D_IN&lt;/code&gt; and &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_CACHEABLE&lt;/code&gt; to an inert value (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_MRDY(i)&lt;='1'&lt;/code&gt;, meaning &#8220;never wait&#8221;, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_D_IN(i)&lt;=&lt;/code&gt;all-ones, and so on) for &lt;strong&gt;every&lt;/strong&gt; core, then overwrites only the current master's own entry with the real, top-level signal &#8212; &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_MRDY (SIGNAL_LAST_ACTIVE_CPU) &lt;= MRDY&lt;/code&gt;, and likewise for the other three. A core that does not currently hold the bus is therefore never stalled by a memory transaction it is not even part of; it keeps running against its own private L1 cache exactly as if it were the only core in the system. The chip-level &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;MMU_MRDY&lt;/code&gt; output follows the identical idiom, one level up &#8212; &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;MMU_MRDY &lt;= CORE_MMU_MRDY(SIGNAL_LAST_ACTIVE_CPU)&lt;/code&gt; &#8212; deliberately &lt;strong&gt;not&lt;/strong&gt; an &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;OR&lt;/code&gt; across all cores, since that would only stay correct for as long as every non-master core's own &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CORE_MMU_MRDY&lt;/code&gt; output happens to be an unconditional &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'1'&lt;/code&gt; (a property of &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;63F29.vhd&lt;/code&gt;, not guaranteed by the arbiter itself).&lt;/p&gt;
&lt;p&gt;The chip-level bus signals proper &#8212; &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E_n&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;Q&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;RW_n&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;A&lt;/code&gt;/ &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;D_OUT&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BA&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BS&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;FIC&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;VMA&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;MEMCLK&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CLKVECT&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_MASTER&lt;/code&gt; &#8212; are all simply the current master's own per-core signals, muxed by &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;SIGNAL_LAST_ACTIVE_CPU&lt;/code&gt;: &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E &lt;= CPU_E(SIGNAL_LAST_ACTIVE_CPU)&lt;/code&gt;, and so on for every one of them.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Protecting E across a bus hand-off&lt;/h2&gt;
&lt;p&gt;Each core keeps generating its own local &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E_LOCAL&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E_n_LOCAL&lt;/code&gt; continuously, bus or no bus &#8212; a core not holding the bus still runs against its own cache. But the &lt;strong&gt;instant&lt;/strong&gt; a core is granted the bus, its own local &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E&lt;/code&gt; phase may not line up cleanly with the moment ownership actually changed hands. A small per-core shift register guards against this:&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre class='spip_code spip_code_block' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;if BUS_GRANTED(i) = '1' then if REGISTER_BUS_GRANTED(1) = '0' then CPU_E(i) &lt;= '1'; CPU_E_n(i) &lt;= '0'; -- held, right after the grant else CPU_E(i) &lt;= E_LOCAL; CPU_E_n(i) &lt;= E_n_LOCAL; -- settled, pass through end if; else CPU_E(i) &lt;= E_LOCAL; CPU_E_n(i) &lt;= E_n_LOCAL; -- not the master: always local end if;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;REGISTER_BUS_GRANTED&lt;/code&gt; is a 2-bit shift register, sampling &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_GRANTED(i)&lt;/code&gt; on the falling edge of each of the four &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CLKVECT&lt;/code&gt; phases in turn. Right after a grant, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_E(i)&lt;/code&gt; is held high for as long as &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_GRANTED(i)&lt;/code&gt; has not yet been seen stably asserted across two such samples; once it has, the core's real &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E_LOCAL&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E_n_LOCAL&lt;/code&gt; is allowed through as the externally-visible &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_E(i)&lt;/code&gt;. The register is reset the instant &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_GRANTED(i)&lt;/code&gt; falls back to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'0'&lt;/code&gt;, so the very next hand-off to this core goes through the same settling window again.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;The lock mechanism&lt;/h2&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;LOCK_REQUEST&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;LOCK_GRANTED&lt;/code&gt; give a core a way to hold the bus for an indivisible sequence (for instance an atomic read-modify-write, or the dedicated &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;LOCK&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;UNLOCK&lt;/code&gt; instructions). The arbiter treats a lock request exactly like a bus request for the purpose of keeping a core selected &#8212; either one is enough to make the round-robin search stop on that core &#8212; and grants it in the very same one-hot process as &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_GRANTED&lt;/code&gt;, at the same index. As long as a core keeps &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;LOCK_REQUEST&lt;/code&gt; asserted, the sticky round robin above guarantees no other core can become &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;SIGNAL_LAST_ACTIVE_CPU&lt;/code&gt; in between.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="en">
		<title>DMC 63F41</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/dmc-63f41</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/dmc-63f41</guid>
		<dc:date>2024-08-23T17:22:01Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>
&lt;p&gt;The 63F09 L1 data cache (&lt;span class=&#034;caps&#034;&gt;DMC&lt;/span&gt; 63F41) &lt;br class='autobr' /&gt;
Each 63F09 core embeds its own private L1 data cache. It is a direct-mapped, write-through cache: every store is propagated to external memory immediately, and no dirty write-back ever happens. &lt;br class='autobr' /&gt;
A write-back policy would require flushing on every context switch and would delay writes aimed at memory-mapped peripherals &#8212; both unacceptable for this design. Write-through sidesteps both problems at the cost of writing external memory on every store, hit or&#160;(&#8230;)&lt;/p&gt;


-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;h2 class=&#034;spip&#034;&gt;The 63F09 L1 data cache (&lt;span class=&#034;caps&#034;&gt;DMC&lt;/span&gt; 63F41)&lt;/h2&gt;
&lt;p&gt;Each 63F09 core embeds its own private L1 data cache. It is a &lt;strong&gt;direct-mapped, write-through&lt;/strong&gt; cache: every store is propagated to external memory immediately, and &lt;strong&gt;no dirty write-back ever happens&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A write-back policy would require flushing on every context switch and would delay writes aimed at memory-mapped peripherals &#8212; both unacceptable for this design. Write-through sidesteps both problems at the cost of writing external memory on every store, hit or miss.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Address layout and storage&lt;/h2&gt;
&lt;p&gt;A physical address is 36 bits, split as:&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt;&lt;strong&gt;&lt;span class=&#034;caps&#034;&gt;TAG&lt;/span&gt;&lt;/strong&gt; &#8212; 20 bits, upper address bits&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;span class=&#034;caps&#034;&gt;BLOCK&lt;/span&gt;&lt;/strong&gt; &#8212; 16 bits, lower address bits, used directly as the row index into the cache&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Because &lt;span class=&#034;caps&#034;&gt;BLOCK&lt;/span&gt; covers the entire low 16 bits of the address with no further line/offset structure, the cache holds &lt;strong&gt;one row per byte&lt;/strong&gt; over a 64 &lt;span class=&#034;caps&#034;&gt;KB&lt;/span&gt; window &#8212; there is no cache-line granularity beyond a single byte. Two block RAMs are addressed in parallel by the same &lt;span class=&#034;caps&#034;&gt;BLOCK&lt;/span&gt; index:&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;VALID_64k&lt;/code&gt; (component &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;RAM_61F64x1&lt;/code&gt;) &#8212; one bit of &lt;strong&gt;&lt;span class=&#034;caps&#034;&gt;VALID&lt;/span&gt;&lt;/strong&gt;, the 20-bit &lt;strong&gt;&lt;span class=&#034;caps&#034;&gt;TAG&lt;/span&gt;&lt;/strong&gt;, and one &lt;strong&gt;&lt;span class=&#034;caps&#034;&gt;DIRTY&lt;/span&gt;&lt;/strong&gt; bit per other core in the system, for every block index&lt;/li&gt;&lt;li&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CACHE_64K&lt;/code&gt; (component &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;RAM_61F512&lt;/code&gt;) &#8212; the cached data byte itself, for every block index&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Both are true block RAMs, clocked by the same signal, so a tag lookup and a data lookup for the same block always complete together.&lt;/p&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CURRENT_TAG&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CURRENT_BLOCK&lt;/code&gt; are pure combinational functions of the &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt;'s own address bus &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_A&lt;/code&gt; &#8212; they track the &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt;'s requested address instantly, with no latency of their own.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;State machine and the fast-path budget&lt;/h2&gt;
&lt;p&gt;The controller is a state machine with a strict latency budget for the common case: &lt;strong&gt;a cache hit costs exactly one &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; cycle&lt;/strong&gt;, no more (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IDLE&lt;/code&gt; or &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IDLE_2&lt;/code&gt; &#8594; &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;COMPARE_TAG&lt;/code&gt; &#8594; &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;READ_CACHE&lt;/code&gt; &#8594;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;READ_CACHE_2&lt;/code&gt;), four ticks, atching one full rotation of the four phase-shifted clocks that also drive the &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt;'s own &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E&lt;/code&gt; clock. &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IDLE&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IDLE_2&lt;/code&gt; are two functionally identical states that simply alternate to balance clock-tree fan-out while the &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; address is unchanged or &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_VMA&lt;/code&gt; is deasserted; as soon as a new address is presented, the machine moves to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;COMPARE_TAG&lt;/code&gt;.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Read hit&lt;/h2&gt;
&lt;p&gt;In &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;COMPARE_TAG&lt;/code&gt;, for a &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; read, the controller compares the requested tag against the stored one.&lt;/p&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;DIRTY_FLAG&lt;/code&gt; folds in the cross-core coherency state: even a matching, valid tag is treated as a miss if another core has more recently written that same block. On a genuine hit, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_REQUEST&lt;/code&gt; is deasserted, the external address bus is disabled, and the machine proceeds straight to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;READ_CACHE&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;READ_CACHE_2&lt;/code&gt;, which simply present &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CACHE_D_OUT&lt;/code&gt; (the data &lt;span class=&#034;caps&#034;&gt;BRAM&lt;/span&gt;'s output) to the &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; as &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CPU_D_IN&lt;/code&gt; and resynchronize the machine on the &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt;'s own &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E&lt;/code&gt; clock before returning to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IDLE&lt;/code&gt;. &lt;strong&gt;A cache hit therefore costs exactly one &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; cycle&lt;/strong&gt;, matching what a direct, uncached read would already cost &#8212; the cache adds no overhead of its own on the hit path.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Read miss&lt;/h2&gt;
&lt;p&gt;If the tag does not match, is not valid, or is marked dirty by another core, the controller requests the external bus and, once granted, moves to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;ALLOCATE&lt;/code&gt;. &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;ALLOCATE&lt;/code&gt; drives the real address out and waits for the external memory's own ready signal (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;MRDY&lt;/code&gt;, self-looping on &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;ALLOCATE&lt;/code&gt; while it is low); once ready, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;ALLOCATE_2&lt;/code&gt; both hands the fetched data to the &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; &lt;strong&gt;and&lt;/strong&gt; writes it into the cache in the same cycle before returning to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IDLE&lt;/code&gt;. A block that is not cacheable (peripheral space, for instance) is simply never marked valid, so it is always re-fetched. &lt;strong&gt;Populating a new cache entry this way costs 1.5 &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; cycles&lt;/strong&gt; in the fast case &#8212; bus already free, external memory ready without extra wait &#8212; on top of the read itself; a busy bus or a slower external memory extends this by however long &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;BUS_GRANTED&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;MRDY&lt;/code&gt; actually take to arrive.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Write (always write-through)&lt;/h2&gt;
&lt;p&gt;&lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; writes never distinguish hit from miss: a store always goes both to the cache row &lt;strong&gt;and&lt;/strong&gt; out to external memory, in the same transaction. From &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;COMPARE_TAG&lt;/code&gt;, the controller requests the bus and, once granted, enters &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;WRITE_THROUGH&lt;/code&gt;, which drives the address and data out and updates the cache, in the very same cycle it exits toward &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;WRITE_THROUGH_2&lt;/code&gt;. &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;WRITE_THROUGH_2&lt;/code&gt; (and, on multi-core configurations, an extra &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;WRITE_THROUGH_3&lt;/code&gt; resync tick &#8212; see below) waits for the external write to actually complete before returning to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IDLE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because the write is unconditional (never gated on a hit), external memory is guaranteed to always hold the up-to-date value for everyaddress ever written &#8212; the precondition that lets the cache skip any write-back logic entirely.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Cross-core invalidation&lt;/h2&gt;
&lt;p&gt;On a multi-core build, each core's cache carries one &lt;strong&gt;&lt;span class=&#034;caps&#034;&gt;DIRTY&lt;/span&gt;&lt;/strong&gt; bit per &lt;strong&gt;other&lt;/strong&gt; core for every block, plus a matching &lt;strong&gt;Cross Cache Signaling&lt;/strong&gt; (&lt;span class=&#034;caps&#034;&gt;CCS&lt;/span&gt;) bus that broadcasts every write to all other cores:&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CCS_WRITE_PULSE&lt;/code&gt; &#8212; a single-tick pulse, raised exactly on the&lt;br class='autobr' /&gt;
&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;WRITE_THROUGH&lt;/code&gt;&#8594;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;WRITE_THROUGH_2&lt;/code&gt; transition (never earlier), because that is the one point where the bus is already known to be granted and the write is certain to actually happen &#8212; broadcasting any earlier would risk announcing a write that never occurs.&lt;/li&gt;&lt;li&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CCS_ADDRESS_OUT&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CCS_ADDRESS_RW_n_OUT&lt;/code&gt; &#8212; the written address and direction, broadcast alongside the pulse, received by every other core as &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CCS_ADDRESS_IN(i)&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CCS_ADDRESS_RW_n_IN(i)&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Each core runs a separate &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;EXTERNAL_DIRTY_SUPERVISION&lt;/code&gt; process per remote core, watching this broadcast. It reads its own tag/valid &lt;span class=&#034;caps&#034;&gt;BRAM&lt;/span&gt;&lt;br class='autobr' /&gt;
through a second port at the broadcast block index; if the tag matches and the entry is valid, it sets its own &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;DIRTY_OUT(i)&lt;/code&gt; bit for that block. Back in &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;COMPARE_TAG&lt;/code&gt;, any core's own read hit test folds in every other core's dirty bit for the block &#8212; a block flagged dirty by a peer is treated as a miss and re-fetched from external memory, guaranteeing the freshest value is picked up rather than a stale local copy.&lt;/p&gt;
&lt;p&gt;This snoop path has its own read-latency compensation (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;COMPARE_TAG_2&lt;/code&gt;, an explicit extra settling tick before trusting &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;TAG_DIRTY_OUT&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CCS_VALID&lt;/code&gt;), deliberately added because this particular path carries no &#8220;one &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; cycle&#8221; budget constraint &#8212; unlike the &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt;-facing hit/miss path described above, which cannot afford it at all.&lt;/p&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;LOCAL_CACHE_MRDY&lt;/code&gt; further gates the whole state-commit process on multi-core builds: a core only advances its own state machine while every peer reports &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CCS_MRDY_IN(i)='1'&lt;/code&gt;, so no core commits mid-way through a cross-core invalidation window. On single-core builds (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;NCPUS=1&lt;/code&gt;), all of this collapses away &#8212; &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CACHE_MRDY&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;LOCAL_CACHE_MRDY&lt;/code&gt; are simply tied to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'1'&lt;/code&gt;, and &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;DIRTY_FLAG&lt;/code&gt; is always false.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="en">
		<title>RAM 61F512</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/ram-61f512</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/ram-61f512</guid>
		<dc:date>2024-06-14T06:37:13Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>

-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>
		</content:encoded>


		

	</item>
<item xml:lang="en">
		<title>ROM 27F512</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/rom-27f512</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/rom-27f512</guid>
		<dc:date>2024-06-14T06:36:44Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>
&lt;p&gt;System on chip contains a 64 Kbytes &lt;span class=&#034;caps&#034;&gt;ROM&lt;/span&gt; between $&lt;span class=&#034;caps&#034;&gt;FFFF0000&lt;/span&gt; and $&lt;span class=&#034;caps&#034;&gt;FFFFFFFF&lt;/span&gt;. Memory is created with &lt;span class=&#034;caps&#034;&gt;RAM&lt;/span&gt; blocks in a read only configuration. &lt;br class='autobr' /&gt;
This &lt;span class=&#034;caps&#034;&gt;ROM&lt;/span&gt; is hardcoded and initialized with memblcks.rpl.&lt;/p&gt;


-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;System on chip contains a 64 Kbytes &lt;span class=&#034;caps&#034;&gt;ROM&lt;/span&gt; between $&lt;span class=&#034;caps&#034;&gt;FFFF0000&lt;/span&gt; and $&lt;span class=&#034;caps&#034;&gt;FFFFFFFF&lt;/span&gt;. Memory is created with &lt;span class=&#034;caps&#034;&gt;RAM&lt;/span&gt; blocks in a read only configuration.&lt;/p&gt;
&lt;p&gt;This &lt;span class=&#034;caps&#034;&gt;ROM&lt;/span&gt; is hardcoded and initialized with &lt;a href='https://63f09.systella.fr/soc-63f09/tools/article/rom-initialization' class=&#034;spip_in&#034;&gt;memblcks.rpl&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="en">
		<title>MMU 63F29</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/mmu-63f29</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/mmu-63f29</guid>
		<dc:date>2024-06-14T06:35:58Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>
&lt;p&gt;* Adresse du vecteur &lt;span class=&#034;caps&#034;&gt;RESET&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;ORG&lt;/span&gt; $&lt;span class=&#034;caps&#034;&gt;FFFF0010&lt;/span&gt; &lt;br class='autobr' /&gt; &lt;span class=&#034;caps&#034;&gt;LDMD&lt;/span&gt; #$31 &lt;br class='autobr' /&gt;
* Ring 0 : on mappe la page des vecteurs d'interruption, &lt;span class=&#034;caps&#034;&gt;MMU&lt;/span&gt; inactive &lt;span class=&#034;caps&#034;&gt;LDQ&lt;/span&gt; #$&lt;span class=&#034;caps&#034;&gt;FFFFFF00&lt;/span&gt; ; adresse logique que l'on doit atteindre. ; seuls les bits 31 &#224; 12 sont pertinents, soit ; $&lt;span class=&#034;caps&#034;&gt;FFFF&lt;/span&gt;:F000. &lt;span class=&#034;caps&#034;&gt;STQ&lt;/span&gt; &gt;TAG_STAGING &lt;br class='autobr' /&gt; &lt;span class=&#034;caps&#034;&gt;LDQ&lt;/span&gt; #$&lt;span class=&#034;caps&#034;&gt;09FFFFFF&lt;/span&gt; ; adresse physique de la page. ; $09 : read, always mapped&#160;(&#8230;)&lt;/p&gt;


-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;textarea readonly='readonly' cols='40' rows='126' class='spip_cadre spip_cadre_block' dir='ltr'&gt;* Adresse du vecteur RESET ORG $FFFF0010 LDMD #$31 * Ring 0 : on mappe la page des vecteurs d'interruption, MMU inactive LDQ #$FFFFFF00 ; adresse logique que l'on doit atteindre. ; seuls les bits 31 &#224; 12 sont pertinents, soit ; $FFFF:F000. STQ &gt;TAG_STAGING LDQ #$09FFFFFF ; adresse physique de la page. ; $09 : read, always mapped ; $FFFFFF : adresse de la page physique permettant ; &#224; la MMU de g&#233;n&#233;rer $F:FFFF:Fxxx. STQ &gt;IND_RING0 * Ring 0 : on mappe la page de code actuel (adresse physique $(F)FFFF0010) LDQ #$FFFF0000 STQ &gt;TAG_STAGING LDQ #$0DFFFFF0 ; $FFFF:0000 =&gt; $F:FFFF:0000 STQ &gt;IND_RING0 * Ring 0 : on mappe les deux pages pour le saut dans le ring 1 : * - $00000000-$00000FFF : pile * - $00001000-$00001FFF : programme LDQ #$00000000 STQ &gt;TAG_STAGING ; read + write + always mapped 0000 1011 LDQ #$0BFFFFF2 ; $0000:0000 =&gt; $F:FFFF:2000 STQ &gt;IND_RING1 LDQ #$00001000 STQ &gt;TAG_STAGING ; read + execute + always mapped 0000 1101 LDQ #$0DFFFFF3 ; $0000:1000 =&gt; $F:FFFF:3000 STQ &gt;IND_RING1 * Ring 0 : on mappe la routine SWI &#224; l'adresse $FFFF:8000 LDQ #$FFFF8000 STQ &gt;TAG_STAGING ; read + execute + always mapped 0000 1101 LDQ #$0DFFFFF8 ; $FFFF:8000 =&gt; $F:FFFF:8000 STQ &gt;IND_RING0 * Ring 0 : on mappe la MMU0 LDQ #$FFFD0000 STQ &gt;TAG_STAGING ; read + write + always mapped 0000 1011 LDQ #$0BFFFFD0 ; $FFFD:0000 =&gt; $F:FFFD:0000 STQ &gt;IND_RING0 * Passage dans le ring 1 ; LDA imm&#233;diat 2 cycles, STA &#233;tendu 7 cycles, JMP &#233;tendu 6 cycles LDA #15 ; 7+2+6 STA &gt;FUSE LDA #$81 STA &gt;MMU0 JMP &gt;$00001000 * Le registre FUSE fait que l'on saute dans le ring 1 &#224; cet instant. * Programme &#233;crit &#224; l'adresse $(F)FFFF3000 mais mapp&#233; &#224; l'adresse $00001000. * &#192; partir de l&#224;, on est prot&#233;g&#233; par la MMU. ORG $FFFF3000 RING0: LDS #$0001000 SWI FCB $CF ORG $FFFFF000 PFHANDLER: LDV #$DEADBEEF FCB $CF ; opcode invalide -&gt; arrete le simulateur ORG $FFFF8000 SWITCH_HANDLER: * On est ici dans le ring 0 parce qu'on vient de SWI. On * va tenter de retourner dans le ring 1. LDA #10 ; 2+7+1 STA &gt;FUSE LDA #$81 ; 2 STA &gt;MMU0 ; 7 RTI ; RTI ne prend qu'un seul cycle dans le ring courant. MMU0 EQU $FFFD0000 FUSE EQU MMU0+1 TAG_STAGING EQU MMU0+4 IND_RING0 EQU MMU0+$800 IND_RING1 EQU MMU0+$A00 IND_RING2 EQU MMU0+$C00 IND_RING3 EQU MMU0+$E00 ORG $FFFFFFF0 FDB PFHANDLER ; interruption 0 : TRAP / DIV0 / PAGEFAULT FDB $0000 ; SWI3 FDB $0000 ; SWI2 FDB $0000 ; FIRQ FDB $0000 ; IRQ FDB SWITCH_HANDLER ; SWI FDB $0000 ; NMI FDB $0010 ; RESET END&lt;/textarea&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="en">
		<title>SPI 63F52</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/spi-63f52</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/spi-63f52</guid>
		<dc:date>2024-06-14T06:35:26Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>
&lt;p&gt;This controller acts as master or slave &lt;span class=&#034;caps&#034;&gt;SPI&lt;/span&gt; device. External signals &lt;span class=&#034;caps&#034;&gt;MISO&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;MOSI&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;SCLK&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;CS&lt;/span&gt; (16 bits) &lt;br class='autobr' /&gt;
In slave mode, &lt;span class=&#034;caps&#034;&gt;CS&lt;/span&gt;(0) is mandatory SS_n signal. In master mode, &lt;span class=&#034;caps&#034;&gt;CS&lt;/span&gt; is used to address slaves's chip select lines. This controller can directly drive 16 &lt;span class=&#034;caps&#034;&gt;SPI&lt;/span&gt; slaves or more slave with an additional address decoder. Internal registers Registers Address Access 7 6 5 4 3 2 1 0 base + 0 when &lt;span class=&#034;caps&#034;&gt;CC&lt;/span&gt;(0) = 0 read &lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; register write &lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; register base + 0 when &lt;span class=&#034;caps&#034;&gt;CC&lt;/span&gt;(0) = 1&#160;(&#8230;)&lt;/p&gt;


-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;This controller acts as master or slave &lt;span class=&#034;caps&#034;&gt;SPI&lt;/span&gt; device.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt; External signals &lt;/h2&gt;&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; &lt;span class=&#034;caps&#034;&gt;MISO&lt;/span&gt;&lt;/li&gt;&lt;li&gt; &lt;span class=&#034;caps&#034;&gt;MOSI&lt;/span&gt;&lt;/li&gt;&lt;li&gt; &lt;span class=&#034;caps&#034;&gt;SCLK&lt;/span&gt;&lt;/li&gt;&lt;li&gt; &lt;span class=&#034;caps&#034;&gt;CS&lt;/span&gt; (16 bits)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;In slave mode, &lt;span class=&#034;caps&#034;&gt;CS&lt;/span&gt;(0) is mandatory SS_n signal. In master mode, &lt;span class=&#034;caps&#034;&gt;CS&lt;/span&gt; is used to address slaves's chip select lines. This controller can directly drive 16 &lt;span class=&#034;caps&#034;&gt;SPI&lt;/span&gt; slaves or more slave with an additional address decoder.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt; Internal registers &lt;/h2&gt;&lt;table class=&#034;table spip&#034;&gt;
&lt;caption&gt;Registers&lt;/caption&gt;
&lt;thead&gt;&lt;tr class='row_first'&gt;&lt;th id='idb81d_c0'&gt; Address &lt;/th&gt;&lt;th id='idb81d_c1'&gt; Access &lt;/th&gt;&lt;th id='idb81d_c2'&gt; 7 &lt;/th&gt;&lt;th id='idb81d_c3'&gt; 6 &lt;/th&gt;&lt;th id='idb81d_c4'&gt; 5 &lt;/th&gt;&lt;th id='idb81d_c5'&gt; 4 &lt;/th&gt;&lt;th id='idb81d_c6'&gt; 3 &lt;/th&gt;&lt;th id='idb81d_c7'&gt; 2 &lt;/th&gt;&lt;th id='idb81d_c8'&gt; 1 &lt;/th&gt;&lt;th id='idb81d_c9'&gt; 0 &lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td rowspan='2' headers='idb81d_c0'&gt;base + 0 when &lt;span class=&#034;caps&#034;&gt;CC&lt;/span&gt;(0) = 0&lt;/td&gt;
&lt;td headers='idb81d_c1'&gt;read&lt;/td&gt;
&lt;td colspan='8' headers='idb81d_c2'&gt;&lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; register&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td headers='idb81d_c1'&gt;write&lt;/td&gt;
&lt;td colspan='8' headers='idb81d_c2'&gt;&lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; register&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td headers='idb81d_c0'&gt;base + 0 when &lt;span class=&#034;caps&#034;&gt;CC&lt;/span&gt;(0) = 1&lt;/td&gt;
&lt;td headers='idb81d_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb81d_c2'&gt;Clock divisor (&lt;span class=&#034;caps&#034;&gt;MSB&lt;/span&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td rowspan='2' headers='idb81d_c0'&gt;base + 1&lt;/td&gt;
&lt;td rowspan='2' headers='idb81d_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb81d_c2'&gt;Control register&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td headers='idb81d_c2'&gt;BUSY_n/&lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; data ready&lt;/td&gt;
&lt;td headers='idb81d_c3'&gt;&lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; empty&lt;/td&gt;
&lt;td headers='idb81d_c4'&gt;&lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;IRQ&lt;/span&gt; enabled&lt;/td&gt;
&lt;td headers='idb81d_c5'&gt;&lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;IRQ&lt;/span&gt; enabled&lt;/td&gt;
&lt;td headers='idb81d_c6'&gt;&lt;span class=&#034;caps&#034;&gt;CPOL&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb81d_c7'&gt;&lt;span class=&#034;caps&#034;&gt;CPHA&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb81d_c8'&gt;Slave &lt;span class=&#034;caps&#034;&gt;SPI&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb81d_c9'&gt;Clock divisor access&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td headers='idb81d_c0'&gt;base + 1 when &lt;span class=&#034;caps&#034;&gt;CC&lt;/span&gt;(0) = 1&lt;/td&gt;
&lt;td headers='idb81d_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb81d_c2'&gt;Clock divisor (&lt;span class=&#034;caps&#034;&gt;LSB&lt;/span&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td headers='idb81d_c0'&gt;base + 2 when &lt;span class=&#034;caps&#034;&gt;CC&lt;/span&gt;(0) = 0&lt;/td&gt;
&lt;td headers='idb81d_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb81d_c2'&gt;Chip select register (&lt;span class=&#034;caps&#034;&gt;MSB&lt;/span&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td headers='idb81d_c0'&gt;base + 3 when &lt;span class=&#034;caps&#034;&gt;CC&lt;/span&gt;(0) = 0&lt;/td&gt;
&lt;td headers='idb81d_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb81d_c2'&gt;Chip select register (&lt;span class=&#034;caps&#034;&gt;LSB&lt;/span&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;h2 class=&#034;spip&#034;&gt; Notes &lt;/h2&gt;
&lt;p&gt;Please note that &lt;span class=&#034;caps&#034;&gt;CS&lt;/span&gt;(0) is only used to read or write clock divisor register. This bit returns to 0 after first access to clock register (&lt;span class=&#034;caps&#034;&gt;LSB&lt;/span&gt;). Chip select register cannot be selected when &lt;span class=&#034;caps&#034;&gt;CS&lt;/span&gt;(0) = 1 (write operation is ignored and read operation always returns $00).&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="en">
		<title>TWI (i2c) 63F54</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/twi-i2c-63f54</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/twi-i2c-63f54</guid>
		<dc:date>2024-06-14T06:35:04Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>
&lt;p&gt;Internal registers Registers Address Access 7 6 5 4 3 2 1 0 base + 0 read &lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; register write &lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; register base + 1 read Current start register (cleared when transaction begins) write Start register &lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt; [1] &lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt; soft reset stop after slave's ack master ack read/not write start request base + 2 read/write Control register &lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; data ready &lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; empty &lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;IRQ&lt;/span&gt; enabled &lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;IRQ&lt;/span&gt; enabled &lt;span class=&#034;caps&#034;&gt;ACK&lt;/span&gt; received &lt;span class=&#034;caps&#034;&gt;ACK&lt;/span&gt; error busy 10 bits address base + 3 read Status register &lt;span class=&#034;caps&#034;&gt;READY&lt;/span&gt;&#160;(&#8230;)&lt;/p&gt;


-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;h2 class=&#034;spip&#034;&gt;Internal registers&lt;/h2&gt;&lt;table class=&#034;table spip&#034;&gt;
&lt;caption&gt;Registers&lt;/caption&gt;
&lt;thead&gt;&lt;tr class='row_first'&gt;&lt;th id='idb2e1_c0'&gt; Address &lt;/th&gt;&lt;th id='idb2e1_c1'&gt; Access &lt;/th&gt;&lt;th id='idb2e1_c2'&gt; 7 &lt;/th&gt;&lt;th id='idb2e1_c3'&gt; 6 &lt;/th&gt;&lt;th id='idb2e1_c4'&gt; 5 &lt;/th&gt;&lt;th id='idb2e1_c5'&gt; 4 &lt;/th&gt;&lt;th id='idb2e1_c6'&gt; 3 &lt;/th&gt;&lt;th id='idb2e1_c7'&gt; 2 &lt;/th&gt;&lt;th id='idb2e1_c8'&gt; 1 &lt;/th&gt;&lt;th id='idb2e1_c9'&gt; 0 &lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td rowspan='2' headers='idb2e1_c0'&gt;base + 0&lt;/td&gt;
&lt;td headers='idb2e1_c1'&gt;read&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; register&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td headers='idb2e1_c1'&gt;write&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; register&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td rowspan='3' headers='idb2e1_c0'&gt;base + 1&lt;/td&gt;
&lt;td headers='idb2e1_c1'&gt;read&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;Current start register (cleared when transaction begins)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td rowspan='2' headers='idb2e1_c1'&gt;write&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;Start register&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb2-1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Don't care&#034; id=&#034;nh2-1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c3'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c4'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c5'&gt;soft reset&lt;/td&gt;
&lt;td headers='idb2e1_c6'&gt;stop after slave's ack&lt;/td&gt;
&lt;td headers='idb2e1_c7'&gt;master ack&lt;/td&gt;
&lt;td headers='idb2e1_c8'&gt;read/not write&lt;/td&gt;
&lt;td headers='idb2e1_c9'&gt;start request&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td rowspan='2' headers='idb2e1_c0'&gt;base + 2&lt;/td&gt;
&lt;td rowspan='2' headers='idb2e1_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;Control register&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; data ready&lt;/td&gt;
&lt;td headers='idb2e1_c3'&gt;&lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; empty&lt;/td&gt;
&lt;td headers='idb2e1_c4'&gt;&lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;IRQ&lt;/span&gt; enabled&lt;/td&gt;
&lt;td headers='idb2e1_c5'&gt;&lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;IRQ&lt;/span&gt; enabled&lt;/td&gt;
&lt;td headers='idb2e1_c6'&gt;&lt;span class=&#034;caps&#034;&gt;ACK&lt;/span&gt; received&lt;/td&gt;
&lt;td headers='idb2e1_c7'&gt;&lt;span class=&#034;caps&#034;&gt;ACK&lt;/span&gt; error&lt;/td&gt;
&lt;td headers='idb2e1_c8'&gt;busy&lt;/td&gt;
&lt;td headers='idb2e1_c9'&gt;10 bits address&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td rowspan='12' headers='idb2e1_c0'&gt;base + 3&lt;/td&gt;
&lt;td rowspan='12' headers='idb2e1_c1'&gt;read&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;Status register&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;READY&lt;/span&gt; (00000001)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;READY&lt;/span&gt; (00000001)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;START&lt;/span&gt; (00000010)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;STOP&lt;/span&gt; (00000011)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;READ&lt;/span&gt; (00000100)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;WRITE&lt;/span&gt; (00000101)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;MASTER&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;ACK&lt;/span&gt; (00001000)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;NO&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;MASTER&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;ACK&lt;/span&gt; (00001001)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;SLAVE&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;ACK&lt;/span&gt; after address (00010000)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;SLAVE&lt;/span&gt; &lt;span class=&#034;caps&#034;&gt;ACK&lt;/span&gt; after data (00010001)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;ERROR&lt;/span&gt; (10000000)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td headers='idb2e1_c0'&gt;base + 3&lt;/td&gt;
&lt;td headers='idb2e1_c1'&gt;write&lt;/td&gt;
&lt;td headers='idb2e1_c2'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c3'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c4'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c5'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c6'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c7'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c8'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;
&lt;td headers='idb2e1_c9'&gt;&lt;span class=&#034;caps&#034;&gt;DC&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td headers='idb2e1_c0'&gt;base + 4&lt;/td&gt;
&lt;td headers='idb2e1_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;Clock divisor (&lt;span class=&#034;caps&#034;&gt;MSB&lt;/span&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td headers='idb2e1_c0'&gt;base + 5&lt;/td&gt;
&lt;td headers='idb2e1_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;Clock divisor (&lt;span class=&#034;caps&#034;&gt;LSB&lt;/span&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td headers='idb2e1_c0'&gt;base + 6&lt;/td&gt;
&lt;td headers='idb2e1_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;Slave address (&lt;span class=&#034;caps&#034;&gt;MSB&lt;/span&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td headers='idb2e1_c0'&gt;base + 7&lt;/td&gt;
&lt;td headers='idb2e1_c1'&gt;read/write&lt;/td&gt;
&lt;td colspan='8' headers='idb2e1_c2'&gt;Slave address (&lt;span class=&#034;caps&#034;&gt;LSB&lt;/span&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb2-1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh2-1&#034; class=&#034;spip_note&#034; title=&#034;Footnotes 2-1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Don't care&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="en">
		<title>PTM 63F40</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/ptm-63f40</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/ptm-63f40</guid>
		<dc:date>2024-06-14T06:34:25Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>
&lt;p&gt;This programmable timer has been designed to be compatible with regular &lt;span class=&#034;caps&#034;&gt;MC6840&lt;/span&gt;. &lt;br class='autobr' /&gt;
The programmable timer (&lt;span class=&#034;caps&#034;&gt;PTM&lt;/span&gt; 63F40) &lt;br class='autobr' /&gt;
PTM_63F40 is modelled on the classic 6840 &lt;span class=&#034;caps&#034;&gt;PTM&lt;/span&gt;: three independent timer/counter channels, each with its own control register, 16-bit latch, gate input, clock input, and output pin. &lt;br class='autobr' /&gt;
Three identical channels &lt;br class='autobr' /&gt;
Each channel keeps a 19-bit down-counter (a 16-bit value plus a 3-bit prescale-by-8 tail), reloaded from its own 16-bit latch register whenever it reaches zero, on&#160;(&#8230;)&lt;/p&gt;


-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;This programmable timer has been designed to be compatible with regular &lt;span class=&#034;caps&#034;&gt;MC6840&lt;/span&gt;.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;The programmable timer (&lt;span class=&#034;caps&#034;&gt;PTM&lt;/span&gt; 63F40)&lt;/h2&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;PTM_63F40&lt;/code&gt; is modelled on the classic 6840 &lt;span class=&#034;caps&#034;&gt;PTM&lt;/span&gt;: three independent timer/counter channels, each with its own control register, 16-bit&lt;br class='autobr' /&gt;
latch, gate input, clock input, and output pin.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Three identical channels&lt;/h2&gt;
&lt;p&gt;Each channel keeps a 19-bit down-counter (a 16-bit value plus a 3-bit prescale-by-8 tail), reloaded from its own 16-bit &lt;strong&gt;latch register&lt;/strong&gt; whenever it reaches zero, on reset, or when told to restart. Three things gate whether &#8212; and how &#8212; a channel actually counts:&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt;&lt;strong&gt;Clock source&lt;/strong&gt; (control bit 1) &#8212; either the channel's own external pin &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C_n&lt;/code&gt;, or the shared &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;SYSCLK&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Gate&lt;/strong&gt; (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;G_n&lt;/code&gt;) &#8212; held low, or a fresh negative edge on it, is what lets the counter run at all; the comment in the source is explicit: &#8220;Counter is enabled by an absence of a timer reset condition and a logic zero at the gate input.&#8221;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Mode&lt;/strong&gt; (control bits 5-3) &#8212; &lt;strong&gt;continuous&lt;/strong&gt;: the counter free-runs, auto-reloading and toggling the channel's output (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;O&lt;/code&gt;) and its interrupt flag every time it reaches zero, restarted by a gate edge, a fresh write to the latch, or reset. &lt;strong&gt;Single-shot&lt;/strong&gt;: a small internal state machine (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;STAGE&lt;/code&gt;) produces exactly one active-high pulse on &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;O&lt;/code&gt;, timed by the counter, then returns to idle until the next gate&lt;br class='autobr' /&gt;
edge or latch write starts it again.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Channel 3 has one extra option of its own: control bit 0 lets it decrement by the full 19-bit granularity (one step of the prescaler at a time) instead of the usual 8 &#8212; the mechanism a chained configuration would use to build slower rates out of channel 3's own countdown for the other channels.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Register map&lt;/h2&gt;
&lt;p&gt;Three address bits select, on read, the shared status register or one of the three channels' current 16-bit counter value (high or low byte); writes target the corresponding control register or latch register instead. Reading the status register also latches which of the three channels are pending, for whatever software wants to do with that snapshot (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;PENDING_IRQ&lt;/code&gt;).&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Interrupt aggregation&lt;/h2&gt;
&lt;p&gt;Each channel has its own interrupt-enable bit (control register bit 6) and its own pending flag; the global status register bit 7 is simply the &lt;span class=&#034;caps&#034;&gt;OR&lt;/span&gt; of the three (flag &lt;strong&gt;and&lt;/strong&gt; its own enable), and &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IRQ_n&lt;/code&gt; follows that bit directly once reset is released. As with the other peripherals on this bus, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;MRDY&lt;/code&gt; is tied to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'1'&lt;/code&gt; &#8212; the &lt;span class=&#034;caps&#034;&gt;PTM&lt;/span&gt; never inserts a wait state.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		
		<enclosure url="https://63f09.systella.fr/IMG/pdf/6840.pdf" length="1539219" type="application/pdf" />
		

	</item>
<item xml:lang="en">
		<title>PIA 63F21</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/pia-63f21</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/pia-63f21</guid>
		<dc:date>2024-06-14T06:34:02Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>
&lt;p&gt;This component runs as a regular &lt;span class=&#034;caps&#034;&gt;MC6821&lt;/span&gt;. Please note that 63F21 only contains half &lt;span class=&#034;caps&#034;&gt;MC6821&lt;/span&gt;. &lt;br class='autobr' /&gt;
The parallel interface (&lt;span class=&#034;caps&#034;&gt;PIA&lt;/span&gt; 63F21) &lt;br class='autobr' /&gt;
PIA_63F21 is a peripheral interface adapter modelled on the classic 6821 &lt;span class=&#034;caps&#034;&gt;PIA&lt;/span&gt; &#8212; but, as the source itself warns, only half of one: a single 8-bit bidirectional port with its two handshake lines (C1, C2), not the real chip's two independent ports. &lt;br class='autobr' /&gt;
One port, direction set per bit &lt;br class='autobr' /&gt;
PORT_D is a genuine bidirectional bus, built from one &lt;span class=&#034;caps&#034;&gt;IOBUF&lt;/span&gt; primitive per bit, each&#160;(&#8230;)&lt;/p&gt;


-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;This component runs as a regular &lt;span class=&#034;caps&#034;&gt;MC6821&lt;/span&gt;. Please note that 63F21 only contains half &lt;span class=&#034;caps&#034;&gt;MC6821&lt;/span&gt;.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;The parallel interface (&lt;span class=&#034;caps&#034;&gt;PIA&lt;/span&gt; 63F21)&lt;/h2&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;PIA_63F21&lt;/code&gt; is a peripheral interface adapter modelled on the classic 6821 &lt;span class=&#034;caps&#034;&gt;PIA&lt;/span&gt; &#8212; but, as the source itself warns, &lt;strong&gt;only half of one&lt;/strong&gt;: a single 8-bit bidirectional port with its two handshake lines (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C1&lt;/code&gt;, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C2&lt;/code&gt;), not the real chip's two independent ports.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;One port, direction set per bit&lt;/h2&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;PORT_D&lt;/code&gt; is a genuine bidirectional bus, built from one &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IOBUF&lt;/code&gt; primitive per bit, each individually steered by its own bit of &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;PORT_DDR&lt;/code&gt; (the &lt;strong&gt;Data Direction Register&lt;/strong&gt;): &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'0'&lt;/code&gt; makes that bit an input, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'1'&lt;/code&gt; an output. Reading the port returns either the last value written (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;PORT_DATA&lt;/code&gt;, for output bits) or the live external level (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;PORT_D_IN&lt;/code&gt;, for input bits) &#8212; bit by bit, so a single port can freely mix input and output lines.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Two addresses, disambiguated by the control register&lt;/h2&gt;
&lt;p&gt;The peripheral only exposes two register addresses (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;A='0'&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;A='1'&lt;/code&gt;), and one bit of the &lt;strong&gt;control register&lt;/strong&gt; decides what &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;A='0'&lt;/code&gt; actually reaches:&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt;&lt;strong&gt;Control register&lt;/strong&gt; (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;A='1'&lt;/code&gt;, 6 writable bits plus two read-only flags) &#8212; bit 2 selects whether &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;A='0'&lt;/code&gt; currently means the &lt;span class=&#034;caps&#034;&gt;DDR&lt;/span&gt; or the data port; bit 1 picks which edge of &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C1&lt;/code&gt; counts as active (high-to-low or low-to-high); bit 0 enables the &lt;span class=&#034;caps&#034;&gt;IRQ&lt;/span&gt; this active edge raises; bits 5-3 configure &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C2&lt;/code&gt;, described below. Bits 7 and 6, read only, are the latched &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C1&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C2&lt;/code&gt; interrupt flags themselves.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Data/&lt;span class=&#034;caps&#034;&gt;DDR&lt;/span&gt; register&lt;/strong&gt; (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;A='0'&lt;/code&gt;) &#8212; the data direction register while control bit 2 is &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'0'&lt;/code&gt;, the actual port data once it is &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'1'&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h2 class=&#034;spip&#034;&gt;C1: a pure edge-triggered interrupt input&lt;/h2&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C1&lt;/code&gt; only ever generates an interrupt flag &#8212; it drives nothing back out. Its rising and falling edges are both tracked; whichever one control bit 1 selects as &#8220;active&#8221; sets the &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IRQ1&lt;/code&gt; latch, which stays set until the data port is actually read (&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;PORT_READ&lt;/code&gt;, driven whenever a read with &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CS&lt;/code&gt; asserted targets the data-port address).&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;C2: input or a small set of output behaviours&lt;/h2&gt;
&lt;p&gt;Control bit 5 decides &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C2&lt;/code&gt;'s whole personality: &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'0'&lt;/code&gt; makes it a second edge-triggered interrupt input, exactly like &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C1&lt;/code&gt; (polarity picked by bit 4, latched into &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IRQ2&lt;/code&gt;, cleared the same way by a port read). &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'1'&lt;/code&gt; turns it into an output, and bits 4-3 then pick one of four fixed behaviours: pulse high on a &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C1&lt;/code&gt; active edge and low again on the next port read; toggle low/high once per &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;E&lt;/code&gt; cycle around a port read; or simply drive a fixed &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'0'&lt;/code&gt; or &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'1'&lt;/code&gt;.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Interrupt output&lt;/h2&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IRQ_n&lt;/code&gt; is the &lt;span class=&#034;caps&#034;&gt;OR&lt;/span&gt; of the two latches, each gated by its own enable &#8212; &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IRQ1&lt;/code&gt; by control bit 0, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;IRQ2&lt;/code&gt; by control bit 3, the latter itself only meaningful while &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;C2&lt;/code&gt; is configured as an input (bit 5 clear). The peripheral never inserts wait states of its own &#8212; &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;MRDY&lt;/code&gt; is tied permanently to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'1'&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		
		<enclosure url="https://63f09.systella.fr/IMG/pdf/6821.pdf" length="1246139" type="application/pdf" />
		

	</item>
<item xml:lang="en">
		<title>ACIA 63F50</title>
		<link>https://63f09.systella.fr/soc-63f09/peripherals/article/acia-63f50</link>
		<guid isPermaLink="true">https://63f09.systella.fr/soc-63f09/peripherals/article/acia-63f50</guid>
		<dc:date>2024-06-14T06:33:42Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>en</dc:language>
		<dc:creator>63F09</dc:creator>



		<description>
&lt;p&gt;This asynchronous serial interface has been designed to be compatible with regular &lt;span class=&#034;caps&#034;&gt;MC6850&lt;/span&gt;. &lt;br class='autobr' /&gt;
The serial interface (&lt;span class=&#034;caps&#034;&gt;ACIA&lt;/span&gt; 63F50) &lt;br class='autobr' /&gt;
ACIA_63F50 is a &lt;span class=&#034;caps&#034;&gt;UART&lt;/span&gt; modelled on the classic 6850 &lt;span class=&#034;caps&#034;&gt;ACIA&lt;/span&gt;, drawing on two well-known open designs (a miniUART and John Kent's own 6850 implementation) as a starting point. It exposes the same two-register, software-visible model as the original chip, with one deliberate departure from it. &lt;br class='autobr' /&gt;
Status and control (address + 0) &lt;br class='autobr' /&gt;
Reading this address returns the status&#160;(&#8230;)&lt;/p&gt;


-
&lt;a href="https://63f09.systella.fr/soc-63f09/peripherals/" rel="directory"&gt;Peripherals&lt;/a&gt;


		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;This asynchronous serial interface has been designed to be compatible with regular &lt;span class=&#034;caps&#034;&gt;MC6850&lt;/span&gt;.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;The serial interface (&lt;span class=&#034;caps&#034;&gt;ACIA&lt;/span&gt; 63F50)&lt;/h2&gt;
&lt;p&gt;&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;ACIA_63F50&lt;/code&gt; is a &lt;span class=&#034;caps&#034;&gt;UART&lt;/span&gt; modelled on the classic 6850 &lt;span class=&#034;caps&#034;&gt;ACIA&lt;/span&gt;, drawing on two well-known open designs (a miniUART and John Kent's own 6850 implementation) as a starting point. It exposes the same two-register, software-visible model as the original chip, with one deliberate departure from it.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Status and control (address + 0)&lt;/h2&gt;
&lt;p&gt;Reading this address returns the &lt;strong&gt;status register&lt;/strong&gt; &#8212; interrupt request, receive parity/overrun/framing errors, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CTS&lt;/code&gt; level, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;DCD&lt;/code&gt; level, transmit-buffer-empty, and receive-data-ready, one bit each. Writing it sets the &lt;strong&gt;control register&lt;/strong&gt; instead: an &lt;span class=&#034;caps&#034;&gt;RX&lt;/span&gt;-interrupt enable bit, two bits selecting the &lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt; behaviour (interrupt on/off, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;RTS&lt;/code&gt; asserted or cleared, or a forced break condition), three bits picking the word format (7 or 8 data bits, 1 or 2 stop bits, odd, even or no parity &#8212; eight combinations, matching the original chip's own encoding), and two bits for the baud-rate divider (&#247;1, &#247;16, &#247;64, or a software reset of the whole peripheral).&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Data (address + 1)&lt;/h2&gt;
&lt;p&gt;A read returns the last received character and clears &lt;strong&gt;receive-data-ready&lt;/strong&gt;; a write queues a character for transmission and clears &lt;strong&gt;transmit-buffer-empty&lt;/strong&gt; until it has gone out.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Where this design departs from a real 6850: no external serial clock pins&lt;/h2&gt;
&lt;p&gt;A genuine 6850 takes its transmit and receive bit clocks from external pins. This implementation does not &#8212; the source carries an explicit warning that &lt;strong&gt;serial clocks are generated internally from &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;SYSCLK&lt;/code&gt; and are not available on the serial bus&lt;/strong&gt;. In its place, address + 2 and address + 3 expose a programmable divisor that derives the actual baud clock from &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;SYSCLK&lt;/code&gt; on-chip. Software configures a baud rate by programming this divisor together with the &#247;1/&#247;16/&#247;64 control bits, rather than by wiring an external baud-rate generator to the chip.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;&lt;span class=&#034;caps&#034;&gt;RS232&lt;/span&gt; handshake&lt;/h2&gt;
&lt;p&gt;Beyond &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;RxD&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;TxD&lt;/code&gt; themselves, the peripheral drives &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;RTS_n&lt;/code&gt; from the control register's own &lt;span class=&#034;caps&#034;&gt;TX&lt;/span&gt;-control bits, and reads &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;CTS_n&lt;/code&gt;/&lt;code class='spip_code spip_code_inline' dir='ltr'&gt;DCD_n&lt;/code&gt; back into the status register &#8212; the same modem-control handshake the original 6850 offers, just without a way to drive its own bit-rate off the bus. As with the other peripherals on this bus, &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;MRDY&lt;/code&gt; is tied to &lt;code class='spip_code spip_code_inline' dir='ltr'&gt;'1'&lt;/code&gt;: the &lt;span class=&#034;caps&#034;&gt;ACIA&lt;/span&gt; never inserts a wait state of its own on the &lt;span class=&#034;caps&#034;&gt;CPU&lt;/span&gt; side, independently of how fast the actual serial line runs.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		
		<enclosure url="https://63f09.systella.fr/IMG/pdf/6850.pdf" length="630276" type="application/pdf" />
		

	</item>



</channel>

</rss>
