{"id":59,"date":"2012-04-30T23:27:46","date_gmt":"2012-04-30T23:27:46","guid":{"rendered":"http:\/\/retroramblings.net\/?p=59"},"modified":"2012-05-03T18:01:18","modified_gmt":"2012-05-03T18:01:18","slug":"experimenting-with-tg68","status":"publish","type":"post","link":"http:\/\/retroramblings.net\/?p=59","title":{"rendered":"Experimenting with TG68"},"content":{"rendered":"<h1><strong>Part 1: a counter<\/strong><\/h1>\n<p>The TG68 softcore processor is an MC68000-compatible processor core written by Tobias Gubener, and used in the DE1, DE2 and Turbo Chameleon 64 ports of the Minimig project.\u00a0 The latest version of the core also supports most 68020 instructions,making it a pretty powerful and useful general purpose processor for FPGA applications.<\/p>\n<p>As a learning exercise I wanted to try using the TG68 in a minimal project &#8211; a first step towards the &#8220;build-my-own-computer&#8221; dream I alluded to in an earlier post.<\/p>\n<p>The TG68 consists of two layers &#8211; there&#8217;s the processor core itself which has a pretty simple interface, then there&#8217;s a wrapper which makes it largely signal-compatible with a &#8220;real&#8221; 68k processor.\u00a0 For this project I&#8217;ve used the wrapper &#8211; but later projects will show how the processor can be used &#8220;bare&#8221;.<\/p>\n<p>To test the processor, I&#8217;ve created a very simple program, assembled with <a title=\"A 68K assembler\" href=\"http:\/\/www.easy68k.com\/\" target=\"_blank\">Easy68k<\/a>.<\/p>\n<pre>ORG\u00a0\u00a0 \u00a0$0000\r\n    dc.l      $0      ; Initial Stack Pointer\r\n    dc.l      $8      ; Initial Program Counter\r\nSTART:\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0; first instruction of program\r\n\u00a0\u00a0 \u00a0addq.w\u00a0\u00a0 \u00a0#1,d0\r\n\u00a0\u00a0 \u00a0move.w\u00a0\u00a0 \u00a0d0,$dff180\r\n\u00a0\u00a0 \u00a0bra.s\u00a0\u00a0 \u00a0START\r\n\r\n\u00a0\u00a0 \u00a0END\u00a0\u00a0 \u00a0START\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0; last line of source<\/pre>\n<p>This program runs in a loop which increases register D0 by 1 each iteration, and writes the new value to location $dff180.\u00a0 (This is the location of the background colour register in the Amiga&#8217;s custom chipset &#8211; so this program, running on an Amiga, would result in a colourful flickering screen, similar to many decrunchers back in the day.)<\/p>\n<p>The minimal program above assembles to a mere 5 words:<\/p>\n<pre>$08: $5240\r\n$0A: $33C0\r\n$0C: $00DF\r\n$0E: $F180\r\n$10: $60F6<\/pre>\n<p>(Note that the longword at location 0 is the initial Stack Pointer, and at location 4 is the initial Program Counter, so we start the actual program at location 8.)<\/p>\n<p>In the interests of getting the processor up and running with as little effort at possible, I&#8217;ve not attempted to run the program from RAM &#8211; instead I decode the appropriate addresses directly in VHDL, like so:<\/p>\n<pre>process(clk,cpu_addr)\r\nbegin\r\n\u00a0\u00a0 \u00a0if rising_edge(clk) then\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if cpu_as='0' then\u00a0\u00a0 \u00a0-- The CPU has asserted Address Strobe, so decode the address...\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0case cpu_addr(23 downto 0) is\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0-- We have a simple program encoded into five words here...\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0when X\"000006\" =&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_datain &lt;= X\"0008\"; -- Initial program counter.\u00a0 Initial stack pointer and high word of PC are zero.\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_dtack&lt;='0';\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0when X\"000008\" =&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_datain &lt;= X\"5240\";\u00a0 -- start: addq.w #1,d0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_dtack&lt;='0';\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0when X\"00000A\" =&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_datain &lt;= X\"33c0\";\u00a0 -- move.w d0...\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_dtack&lt;='0';\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0when X\"00000C\" =&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_datain &lt;= X\"00DF\";\u00a0 -- ...\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_dtack&lt;='0';\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0when X\"00000E\" =&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_datain &lt;= X\"F180\";\u00a0 -- ...,$dff180\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_dtack&lt;='0';\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0when X\"000010\" =&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_datain &lt;= X\"60f6\";\u00a0 -- bra.s start\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_dtack&lt;='0';\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0-- Now a simple hardware register at 0xdff180, written to by the program:\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0when X\"dff180\" =&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if cpu_r_w='0' and cpu_uds='0' and cpu_lds='0' then\u00a0\u00a0 \u00a0-- write cycle to the complete word...\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0counter&lt;=cpu_dataout;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_dtack&lt;='0';\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0end if;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0-- For any other address we simply return zero.\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0when others =&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_datain &lt;= X\"0000\";\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_dtack&lt;='0';\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0end case;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0end if;\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0-- When the CPU releases Data Strobe we release dtack.\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0-- (No real need to do this, provided everything responds in a single cycle.\u00a0 DTACK Grounded!)\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if cpu_uds='1' and cpu_lds='1' then\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0cpu_dtack&lt;='1';\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0end if;\r\n\u00a0\u00a0 \u00a0end if;\r\nend process;<\/pre>\n<p>When the processor writes to $dff180, the VHDL snippet above captures the value written, and in the full project writes it to the Hex display on the DE1 board.<\/p>\n<p>The complete Quartus project <a title=\"TG68 test project\" href=\"http:\/\/retroramblings.net\/downloads\/DE1_TG68Test_newcore_68kSig.zip\">can be downloaded here<\/a> if you&#8217;re interested.\u00a0 It runs fast enough that the hex display appears to just read &#8220;8888&#8221;, but if you press Key0, which acts as a reset button, you can freeze the display and read off the number.\u00a0 Signaltap can be used to get a better look at what&#8217;s going on:<\/p>\n<p><a href=\"http:\/\/retroramblings.net\/wp-content\/uploads\/2012\/04\/TG68020_68Ksigs.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-63\" title=\"TG68020_68Ksigs\" src=\"http:\/\/retroramblings.net\/wp-content\/uploads\/2012\/04\/TG68020_68Ksigs-1024x697.jpg\" alt=\"\" width=\"584\" height=\"397\" srcset=\"http:\/\/retroramblings.net\/wp-content\/uploads\/2012\/04\/TG68020_68Ksigs-1024x697.jpg 1024w, http:\/\/retroramblings.net\/wp-content\/uploads\/2012\/04\/TG68020_68Ksigs-300x204.jpg 300w, http:\/\/retroramblings.net\/wp-content\/uploads\/2012\/04\/TG68020_68Ksigs-440x300.jpg 440w, http:\/\/retroramblings.net\/wp-content\/uploads\/2012\/04\/TG68020_68Ksigs.jpg 1148w\" sizes=\"auto, (max-width: 584px) 100vw, 584px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Part 1: a counter The TG68 softcore processor is an MC68000-compatible processor core written by Tobias Gubener, and used in the DE1, DE2 and Turbo Chameleon 64 ports of the Minimig project.\u00a0 The latest version of the core also supports &hellip; <a href=\"http:\/\/retroramblings.net\/?p=59\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,4],"tags":[],"class_list":["post-59","post","type-post","status-publish","format-standard","hentry","category-amiga","category-fpga"],"_links":{"self":[{"href":"http:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/posts\/59","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/retroramblings.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=59"}],"version-history":[{"count":9,"href":"http:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/posts\/59\/revisions"}],"predecessor-version":[{"id":69,"href":"http:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/posts\/59\/revisions\/69"}],"wp:attachment":[{"href":"http:\/\/retroramblings.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=59"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/retroramblings.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=59"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/retroramblings.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=59"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}