perkin.org.uk - A node.js-powered 8-bit CPU - part three









Search Preview

A node.js-powered 8-bit CPU - part three

perkin.org.uk
Jonathan Perkin about me · rss · twitter · github
.org.uk > perkin.org.uk

SEO audit: Content analysis

Language Error! No language localisation is found.
Title A node.js-powered 8-bit CPU - part three
Text / HTML ratio 54 %
Frame Excellent! The website does not use iFrame solutions.
Flash Excellent! The website does not have any flash contents.
Keywords cloud _ » CPU data < pin bus speed clock SmartOS address instruction wired packages > Set Dec pins nop reset
Keywords consistency
Keyword Content Title Description Headings
_ 81
» 52
CPU 35
data 20
< 20
pin 17
Headings
H1 H2 H3 H4 H5 H6
2 4 7 0 0 0
Images We found 5 images on this web page.

SEO Keywords (Single)

Keyword Occurrence Density
_ 81 4.05 %
» 52 2.60 %
CPU 35 1.75 %
data 20 1.00 %
< 20 1.00 %
pin 17 0.85 %
bus 14 0.70 %
speed 14 0.70 %
clock 14 0.70 %
SmartOS 13 0.65 %
address 12 0.60 %
instruction 10 0.50 %
wired 10 0.50 %
packages 10 0.50 %
> 10 0.50 %
Set 10 0.50 %
Dec 9 0.45 %
pins 9 0.45 %
nop 9 0.45 %
reset 9 0.45 %

SEO Keywords (Two Word)

Keyword Occurrence Density
_ _ 20 1.00 %
the CPU 19 0.95 %
2013 » 18 0.90 %
_ < 15 0.75 %
2012 » 14 0.70 %
2011 » 11 0.55 %
we can 11 0.55 %
of the 11 0.55 %
the data 11 0.55 %
data bus 10 0.50 %
to the 9 0.45 %
wired to 9 0.45 %
8bit CPU 9 0.45 %
parseInt1000 speed 8 0.40 %
<> _ 8 0.40 %
on the 8 0.40 %
with the 7 0.35 %
Jun 2011 6 0.30 %
and the 6 0.30 %
at the 6 0.30 %

SEO Keywords (Three Word)

Keyword Occurrence Density Possible Spam
_ _ < 15 0.75 % No
the data bus 10 0.50 % No
<> _ _ 8 0.40 % No
parseInt1000 speed 4 6 0.30 % No
Jan 2013 » 6 0.30 % No
Jun 2011 » 6 0.30 % No
8bit CPU part 5 0.25 % No
nodejspowered 8bit CPU 5 0.25 % No
> _ _ 5 0.25 % No
A nodejspowered 8bit 5 0.25 % No
the reset pin 4 0.20 % No
» A nodejspowered 4 0.20 % No
the CPU is 4 0.20 % No
Dec 2013 » 4 0.20 % No
2013 » A 4 0.20 % No
Jan 2012 » 3 0.15 % No
the hour setTimeoutfunction 3 0.15 % No
» How to 3 0.15 % No
pkgsrc on SmartOS 3 0.15 % No
a nop instruction 3 0.15 % No

SEO Keywords (Four Word)

Keyword Occurrence Density Possible Spam
<> _ _ < 8 0.40 % No
A nodejspowered 8bit CPU 5 0.25 % No
nodejspowered 8bit CPU part 5 0.25 % No
> _ _ < 4 0.20 % No
Dec 2013 » A 4 0.20 % No
2013 » A nodejspowered 4 0.20 % No
» A nodejspowered 8bit 4 0.20 % No
» pkgsrc on SmartOS 3 0.15 % No
2013 » pkgsrc on 3 0.15 % No
= require'rpio' rpiosetOutput11 rpiosetOutput12 2 0.10 % No
elow rpiowrite11 parseInt1000 speed 2 0.10 % No
Jan 2013 » pkgsrc 2 0.10 % No
any of those yet 2 0.10 % No
setTimeoutfunction qlow rpiowrite12 parseInt1000 2 0.10 % No
qlow rpiowrite12 parseInt1000 speed 2 0.10 % No
rpiowrite12 parseInt1000 speed 4 2 0.10 % No
parseInt1000 speed 4 2 2 0.10 % No
Feb 2013 » SmartOS 2 0.10 % No
for the nop instruction 2 0.10 % No
setTimeoutfunction elow rpiowrite11 parseInt1000 2 0.10 % No

Internal links in - perkin.org.uk

about me
About Me
rss
Jonathan Perkin
Reducing RAM usage in pkgin
Reducing RAM usage in pkgin
Building packages at scale
Building packages at scale
A node.js-powered 8-bit CPU - part four
A node.js-powered 8-bit CPU - part four
A node.js-powered 8-bit CPU - part three
A node.js-powered 8-bit CPU - part three
A node.js-powered 8-bit CPU - part two
A node.js-powered 8-bit CPU - part two
A node.js-powered 8-bit CPU - part one
A node.js-powered 8-bit CPU - part one
MDB support for Go
MDB support for Go
Distributed chrooted pkgsrc bulk builds
Distributed chrooted pkgsrc bulk builds
pkgsrc on SmartOS - creating new packages
pkgsrc on SmartOS - creating new packages
Installing SVR4 packages on SmartOS
Installing SVR4 packages on SmartOS
SmartOS is Not GNU/Linux
SmartOS is Not GNU/Linux
SmartOS development preview dataset
SmartOS development preview dataset
pkgsrc on SmartOS - fixing broken builds
pkgsrc on SmartOS - fixing broken builds
pkgsrc on SmartOS - zone creation and basic builds
pkgsrc on SmartOS - zone creation and basic builds
Multi-architecture package support in SmartOS
Multi-architecture package support in SmartOS
Solaris portability - cfmakeraw()
Solaris portability - cfmakeraw()
Solaris portability - flock()
Solaris portability - flock()
SmartOS and the global zone
SmartOS and the global zone
Setting up Samba on SmartOS
Setting up Samba on SmartOS
Creating local SmartOS packages
Creating local SmartOS packages
7,000 binary packages for OSX Lion
7,000 binary packages for OSX Lion
9,000 packages for SmartOS and illumos
9,000 packages for SmartOS and illumos
Goodbye Oracle, Hello Joyent!
Goodbye Oracle, Hello Joyent!
SmartOS global zone tweaks
SmartOS global zone tweaks
Automated VirtualBox SmartOS installs
Automated VirtualBox SmartOS installs
iptables script for Debian / Ubuntu
iptables script for Debian / Ubuntu
New site design
New site design
Set up anonymous FTP upload on Oracle Linux
Set up anonymous FTP upload on Oracle Linux
Kickstart Oracle Linux in VirtualBox
Kickstart Oracle Linux in VirtualBox
Kickstart Oracle Linux from Ubuntu
Kickstart Oracle Linux from Ubuntu
Last day at MySQL
Last day at MySQL
Installing OpenBSD with softraid
Installing OpenBSD with softraid
Create VirtualBox VM from the command line
Create VirtualBox VM from the command line
Creating chroots for fun and MySQL testing
Creating chroots for fun and MySQL testing
Graphing memory usage during an MTR run
Graphing memory usage during an MTR run
Fix input box keybindings in Firefox
Fix input box keybindings in Firefox
How to lose weight
How to lose weight
How to fix stdio buffering
How to fix stdio buffering
Fix Firefox URL double click behaviour
Fix Firefox URL double click behaviour
SSH via HTTP proxy in OSX
SSH via HTTP proxy in OSX
How to build MySQL releases
How to build MySQL releases
ZFS and NFS vs OSX
ZFS and NFS vs OSX
pkgsrc on Solaris
pkgsrc on Solaris
Jumpstart from OSX
Jumpstart from OSX
Set up local caching DNS server on OSX 10.4
Set up local caching DNS server on OSX 10.4

Perkin.org.uk Spined HTML


A node.js-powered 8-bit CPU - part three Jonathan Perkin well-nigh me · rss · twitter · github A node.js-powered 8-bit CPU - part three Dec 03, 2013 tags: 8-bit, homebrew, nodejs This post is part three of a series, the other posts misogynist are Part one - introduction and GPIO Part two - shift registers Part four - putting it all together In part two we synthetic a spin using shift registers whereby we could write a byte of data and then read it when in. In this post we are going to squint at a increasingly complicated integrated spin - a CPU - however the principles are the same. In wing to the pieces required for the first two posts, you will need: An spare specie board.UnbearableLEDs and resistors for 16 increasingly LEDs. A 0.1µF “smoothing” capacitor. An 8-bit CPU. With that said, let’s meet my chosen CPU. 6809/6309 One of the advantages of retro computing is that we can hands (and reasonably cheaply) pick and segregate anything we fancy, and so I’ve chosen the Hitachi 6309, specifically the HD63C09EP. This is Hitachi’s uniform version of the venerable 6809, which is considered by many to be the weightier 8-bit CPU overly made. Hitachi made it plane faster and widow some new instructions and registers, however it was ripened right at the end of the 8-bit era, and with the introduction of 16-bit CPUs soon succeeding it didn’t have time to became as popular as its 8-bit counterparts such as the Z80, 6502 and 8008. Thankfully, it’s still possible to buy them (second hand of course), and I managed to pick one up from littlediode.com for virtually £20. To get started, let’s squint at the pinout and describe what each pin does.Unelevatedis an ASCII diagram, with thanks to Jonathan Bowen’s 6809E transmission (there are scanned PDFs of the original datasheets but the quality is not great). _________ _________ _| \__/ |_ ____ Vss |_| 1 40 |_| Halt <-- ___ _| |_ --> NMI |_| 2 39 |_| TSC <-- ___ _| |_ --> IRQ |_| 3 38 |_| LIC --> ____ _| |_ _____ --> FIRQ |_| 4 37 |_| Reset <-- _| |_ <-- BS |_| 5 36 |_| AVMA --> _| |_ <-- BA |_| 6 35 |_| Q <-- _| |_ Vcc |_| 7 34 |_| E <-- _| |_ <-- A0 |_| 8 33 |_| Busy --> _| |_ _ <-- A1 |_| 9 32 |_| R/W --> _| |_ <-- A2 |_| 10 6809E 31 |_| D0 <--> _| |_ <-- A3 |_| 11 30 |_| D1 <--> _| |_ <-- A4 |_| 12 29 |_| D2 <--> _| |_ <-- A5 |_| 13 28 |_| D3 <--> _| |_ <-- A6 |_| 14 27 |_| D4 <--> _| |_ <-- A7 |_| 15 26 |_| D5 <--> _| |_ <-- A8 |_| 16 25 |_| D6 <--> _| |_ <-- A9 |_| 17 24 |_| D7 <--> _| |_ <-- A10 |_| 18 23 |_| A15 --> _| |_ <-- A11 |_| 19 22 |_| A14 --> _| |_ <-- A12 |_| 20 21 |_| A13 --> |______________________| The arrows denote whether each pin is input, output, or both. Again, if a pin name has a line whilom it, for example Halt, it ways it is “active low” and the function is zingy when the pin is off/low, as opposed to stuff zippy when the pin is on/high. The CPU is placed onto the new specie workbench as shown below, so that the CPU straddles the middle of the breadboard, and the marrow side has increasingly holes misogynist - this helps with wiring as we will need increasingly connections on that side. We can sort the pins into logical groups, for now only concentrating on the yellowish minimum required to get things running. Power (Vss/Pin1, Vcc/Pin7) As with the shift registers, the CPU requires 5V to operate, and so we vaccinate them up directly to the power rails. “Vss” is flipside term for ground. One recommended wing is an 0.1µF capacitor between Vss and Vcc. This acts like a small power buffer, and helps to smooth out any power fluctuations, ensuring that the CPU runs increasingly reliably. Without this, you may notice odd behaviour, expressly if you plug/unplug nearby electric devices. To unzip maximum effectiveness, smoothing capacitors should be placed as tropical as possible to the input pins, as I’ve washed-up in the picture unelevated (again using brown/blue wires to denote power): Clocks (E/Pin34, Q/Pin35) Again, same deal as with the shift registers - the CPU needs a ticking clock in order to momentum the internal circuitry. The 6309 has two clocks which must be driven in a specific order. According to the datasheet “Q must lead E; that is, a transition on Q must be followed by a similar transition on E”. All that ways is that repeating the pursuit sequence is unbearable to momentum the 6309 clock: Set Q upper Set E upper Set Q low Set E low The speed at which we repeat this sequence determines the speed of the CPU. In the past with NMOS designs we would have had to alimony running at a unrepealable frequency for the tweedle to function correctly, but with newer CMOS designs we can run as slowly as we want, which is very helpful for seeing exactly what is happening. By wiring E/Pin34 to GPIO17/Pin11 and Q/Pin35 to GPIO18/Pin12, we can run the CPU at 2Hz (two clock cycles per second) using a slightly extended version of our previous clock code: var rpio = require('rpio'); rpio.setOutput(11); rpio.setOutput(12); /* 2Hz is slow unbearable to see what's happening without stuff overly cautious */ var speed = 2; /* * Our repeating clock. I've used the hour/quarter/half nomenclature as * a helpful visualisation of when each pin fires. setInterval() and * setTimeout() take a millisecond argument, so we use parseInt() to ensure * no floating point. This unquestionably ways we are limited to a clock speed * of 250Hz (one pin waffly every millisecond) if we want a regular cycle. */ setInterval(function clock() { /* Set Q upper immediately (on the hour) */ rpio.write(12, 1); /* Set E upper at quarter past the hour */ setTimeout(function ehigh() { rpio.write(11, 1); }, parseInt(1000 / speed / 4 * 1)); /* Set Q low at half past the hour */ setTimeout(function qlow() { rpio.write(12, 0); }, parseInt(1000 / speed / 4 * 2)); /* Set E low at quarter to the hour */ setTimeout(function elow() { rpio.write(11, 0); }, parseInt(1000 / speed / 4 * 3)); }, parseInt(1000 / speed)); Data Bus (D0-7/Pin31-24) With the 6309 stuff an 8-bit CPU, these are the 8 data pins on which a byte of data is read (“load”) or written (“store”) at a time. These are the only pins which are used for both input and output, and would normally be routed to a static RAM chip. To get a CPU to do some work, we provide instructions (“opcodes”) and operands (an write or a literal value) on the data bus. Let’s start with the simplest program possible, a undeniability to the nop (“No Operation”) instruction: nop ; Do nothing We can hoke this program using Ciaran Anscomb’s asm6809.pl assembler and squint at the machine lawmaking it generated using od. This tells us the respective opcode byte for the nop instruction: :Hokethe source lawmaking in 6309-nop.s into an object file containing raw : binary data. No headers or object format data, just pure instructions. $ asm6809.pl -o 6309-nop 6309-nop.s : Display the contents of the binary in single-byte hexadecimal (-t x1) format. $ od -t x1 6309-nop 0000000 12 0000001 So, to execute a nop instruction on the 6309, we write 0x12 onto the data bus. In the final post I will show how we can use our shift register setup to handle the data bus, however for now we will simply hard-code a nop instruction on the data bus, by wiring each bit either to the +5V or ground planes. To summate the pin settings for writing a particular byte, I wrote a small shell function to convert from hexadecimal to binary: hex2bin8() { printf "%08d\n" $(echo "16 i 2 o $(echo $1 | tr a-z A-Z) p" | dc); } which we can use like so: $ hex2bin8 12 00010010 To execute a nop then, we set D1 and D4 to upper and the rest to low (D0 is the right-most bit, D7 is the left-most bit).Unelevatedis a picture of mine, where I am using the green/white strands of the CAT5 subscription for the data bus connections. Due to the gaps on the power rails, we need to divert the D2 wire up a little to reach the ground rail, however it should hopefully be well-spoken which rail each pin is unfluctuating to.  Address Bus (A0-A15/Pin8-23) Whilst it is an 8-bit CPU, it has a 16-bit write bus, and so is worldly-wise to directly write up to 65536 bytes of memory. The current write stuff read from or written to is output on these pins. Again, these pins would normally be routed to some RAM chip, and by using the write in conjunction with the data bus, we can either load or store one byte of RAM at a time, with the write containing the particular zone of memory to load or store, and the data containing the byte to be read or written. For now, the most useful thing we can do is vaccinate each of these pins up to an LED. By doing this we can simply show what write the CPU is currently at, plane if it does midpoint converting from binary to hex. Here is mine, using orange wire strips to denote the write bus: This can be a bit fiddly, due to the number of wires involved, but it should be possible to wire them all up as shown. Note that the LEDs are when to front in terms of reading binary addresses. We could put them the other way around, but that would require a lot increasingly cabling and it might get messy. This way we moreover match up the orientation of the data bus. If you wanted to get fancy you could instead nail LED segment displays (or nixie tubes!), however I do not have any of those .. yet :) Interrupts (NMI/Pin2, IRQ/Pin3, FIRQ/Pin4) These pins indulge you to send hardware interrupts which interrupt the CPU’s normal operation and execute specific functions. These would normally be used by something like an IO controller to indicate that, for example, some data has been read from disk and is now available. For now we do not need any of these, so we simply disable these by nonflexible wiring them to +5V (they are all active-low). TSC/Pin39 This is the Tri-StateTenancypin, and can be used to synchronize data with other processors or controllers. As we do not have any of those yet, we simply nonflexible wire it to GND and ensure this function is disabled. Halt/Reset (Reset/Pin37, Halt/Pin40) These pins are mostly self-explanatory, and are both active-low. This ways that applying a negative voltage to Reset/Pin37 makes the CPU reset, and to Halt/Pin40 makes it pause indefinitely until Halt is released (set when to high). For now we will alimony things as simple as possible, and wire halt to +5V, powerfully disabling it. We do however need to handle reset, as when the CPU is first powered on it needs a reset trundling to initialise correctly. This is washed-up by holding reset lanugo for at least one clock cycle, and so we will simply vaccinate the reset pin to GPIO21/Pin13 and tenancy this from software. Alternatively, you could wire up a simple binary switch and have a nonflexible reset sawed-off on your board. Pin summary So, at this stage we should have the CPU wired up as following: Power (Vss/Pin1 and Vcc/Pin7) wired to +5V and GND. Clock E/Pin34 wired to GPIO17 (pin 11). Clock Q/Pin35 wired to GPIO18 (pin 12). Data bus (D0-D7/Pin31-24) wired to +5V/GND for 0x12 (“nop”).Writebus (A0-A15/Pin8-23) wired to 16 LEDs. Interrupts (NMI/Pin2, IRQ/Pin3, FIRQ/Pin4) wired to GND. TSC/Pin39 wired to GND. Reset/Pin37 wired to GPIO21 (pin 13). Halt/Pin40 wired to +5V. and the workbench should squint something like this: Software We can proffer our clock example whilom and add handling of the reset pin: var rpio = require('rpio'); rpio.setOutput(11); rpio.setOutput(12); rpio.setOutput(13); // Bump this to 2Hz from the clock example. var speed = 2; // Start with the reset pin held low while we start up the clock. rpio.write(13, 0); // The clock function is the same as before. setInterval(function clock() { rpio.write(12, 1); setTimeout(function ehigh() { rpio.write(11, 1); }, parseInt(1000 / speed / 4 * 1)); setTimeout(function qlow() { rpio.write(12, 0); }, parseInt(1000 / speed / 4 * 2)); setTimeout(function elow() { rpio.write(11, 0); }, parseInt(1000 / speed / 4 * 3)); }, parseInt(1000 / speed)); /* * Ensure we run the clock at least once, then set the reset pin when high, * releasing the CPU to execute normally. */ setTimeout(function resethigh() { rpio.write(13, 1); }, parseInt(2 * 1000 / speed)); Start It Up! We now have everything in place to get the CPU running.Unelevatedis a video of mine, running at 2Hz. At this point we can see and explain what happens right at the start of a CPU’s execution. I’ve trimmed the first second or so from the video where the CPU is running through its pre-initialisation routine. The video starts at the point where the CPU is reading the very first instructions from memory. The 6309 starts by reading a byte each from 0xFFFE and 0xFFFF, and this gives it the first 16-bit write to read from. You can see these first two addresses shown by the LEDs at the whence of the video. Remember that the write LEDs are back-to-front, so the least-significant bit is on the left, not the right. Ordinarily there would be a ROM handling this part, and it would uncontrived the CPU to start reading an zone it has set whispered to store a vital operating system. Once the write has been loaded, the CPU jumps to it and starts reading instructions. As we are hard-coding the data bus with 0x12, the first write that the CPU jumps to is 0x1212, shown by the 00010010 00010010 on the LEDs. At this “address” the CPU then reads data from the data bus ready for its first instruction, and of undertow gets flipside 0x12. This time it is executed as a nop instruction, where the CPU does nothing for an instruction cycle. This pattern then continues indefinitely: The CPU increments the memory location where it should fetch the current instruction from. This is known as the “program counter” or “instruction pointer”. The CPU reads an instruction from that location, in our specimen unchangingly reading 0x12 which is its opcode for the nop instruction. The nop is executed, i.e. nothing happens. Sure, it’s not practically useful. However, we are powering this entirely from JavaScript, we can see exactly what is happening, and for me at least it is immensely helpful having a visual overview of exactly how a CPU works. The next and final step is to make the data bus controllable, so that we can issue wrong-headed instructions and read when results. If only we had some way of reading and writing 8 shit of data using only a couple of GPIO pins… ;) Share this post on Twitter, HackerNews, Facebook or Google+ All Posts 16 Jul 2015 » Reducing RAM usage in pkgin 03 Mar 2015 » pkgsrc-2014Q4: LTS, signed packages, and increasingly 06 Oct 2014 » Building packages at scale 04 Dec 2013 » A node.js-powered 8-bit CPU - part four 03 Dec 2013 » A node.js-powered 8-bit CPU - part three 02 Dec 2013 » A node.js-powered 8-bit CPU - part two 01 Dec 2013 » A node.js-powered 8-bit CPU - part one 21 Nov 2013 » MDB support for Go 30 Jul 2013 » What's new in pkgsrc-2013Q2 24 Jul 2013 » Distributed chrooted pkgsrc zillion builds 07 Jun 2013 » pkgsrc on SmartOS - creating new packages 15 Apr 2013 » What's new in pkgsrc-2013Q1 19 Mar 2013 » Installing SVR4 packages on SmartOS 27 Feb 2013 » SmartOS is Not GNU/Linux 18 Feb 2013 » SmartOS minutiae preview dataset 17 Jan 2013 » pkgsrc on SmartOS - fixing wrenched builds 15 Jan 2013 » pkgsrc on SmartOS - zone megacosm and vital builds 10 Jan 2013 » Multi-architecture package support in SmartOS 09 Jan 2013 » Solaris portability - cfmakeraw() 08 Jan 2013 » Solaris portability - flock() 06 Jan 2013 » pkgsrc-2012Q4 illumos packages now misogynist 23 Nov 2012 » SmartOS and the global zone 24 Oct 2012 » Setting up Samba on SmartOS 10 Oct 2012 » pkgsrc-2012Q3 packages for illumos 23 Aug 2012 » Creating local SmartOS packages 10 Jul 2012 » 7,000 binary packages for OSX Lion 09 Jul 2012 » 9,000 packages for SmartOS and illumos 07 May 2012 » Goodbye Oracle, Hello Joyent! 13 Apr 2012 » SmartOS global zone tweaks 12 Apr 2012 » Automated VirtualBox SmartOS installs 30 Mar 2012 » iptables script for Debian / Ubuntu 20 Feb 2012 » New site diamond 11 Jan 2012 » Set up unrecognized FTP upload on Oracle Linux 09 Jan 2012 » Kickstart Oracle Linux in VirtualBox 09 Jan 2012 » Kickstart Oracle Linux from Ubuntu 22 Dec 2011 » Last day at MySQL 15 Dec 2011 » Installing OpenBSD with softraid 21 Sep 2011 » Create VirtualBox VM from the writ line 14 Sep 2011 » Creating chroots for fun and MySQL testing 30 Jun 2011 » Graphing memory usage during an MTR run 29 Jun 2011 » Fix input box keybindings in Firefox 24 Jun 2011 » How to lose weight 23 Jun 2011 » How to fix stdio buffering 13 Jun 2011 » Serving multiple DNS search domains in IOS DHCP 13 Jun 2011 » Fix Firefox URL double click behaviour 20 Apr 2011 » SSH via HTTP proxy in OSX 09 Nov 2010 » How to build MySQL releases 29 Apr 2010 » 'apt-get' and 5,000 packages for Solaris10/x86 16 Sep 2009 » ZFS and NFS vs OSX 12 Sep 2009 » pkgsrc on Solaris 09 Dec 2008 » Jumpstart from OSX 31 Dec 2007 » Set up local caching DNS server on OSX 10.4