Tuesday, May 30, 2017

TTL Brainfuck Computer Part 4 - Animate Objects

Part 1 (first) - Part 3 (prev) - Part 5 (next)

To breathe life into my CPU, it needs a heartbeat. I put together a simple 555 astable circuit with a 10k potentiometer to adjust the clock speed. I'm still waiting on some switches to put in a manual clock mode.

Since the counter control signals need to be synchronized with the clock, I added a 74LS00 (quad 2-input NAND) to combine the signals. This provides the high signal by default to disable count/load, and only activates (goes low) when both the clock and control signals go high. This "uninverts" the logic of the control signals and confuses me a couple times in the following video:


You'll notice a couple extra jumpers connecting the ground lines on the data register. I'm starting to have some really frustrating issues with these crappy breadboards. Replacements should be here tomorrow.

The LED boards are made from some breadboard-style PCB that came with one of the Elegoo kits. I trimmed the plastic lip with wire nippers so they'd fit snugly. I alternated their orientations so cathode is next to cathode, anode next to anode. Then I put resistors on the underside of the board between the cathodes and the power rail of the PCB. I chopped off the cathode leads, and added a ground connection to the new common cathode. Having 2 anodes side by side with 2 blank spaces between fits perfectly in the outputs of the 193s, and only needs a small bit of bending to fit into the data bus.

I've got a 16-bit one for the data pointer but still need to dremel it down to size.

Part 1 (first) - Part 3 (prev) - Part 5 (next)

TTL Brainfuck Computer Part 3 - First Connections

Part 1 (first) - Part 2 (prev) - Part 4 (next)

After making a pile of insulation confetti, here's a thing that actually does some stuff:



I went ahead and grabbed one of the other 193s to finish up the Data Pointer at the top-left. The output of the counters are connected in purple to the address lines of the Data RAM.

The buttons on the left are connected to Load (orange), Clear (white), Down (red/blue) and Up (green/yellow). This allows me to easily cycle through memory addresses. Load, Down, & Up are active low, so they've got pull-up resistors to +5V. Clear is pulled low.

The I/O pins of the RAM are connected to the data bus. The three jumper wires coming out of the ram are Load (orange), Output Enable (blue), and Chip Enable (yellow). These are all active low, so currently it's sending whatever value is being pointed to in RAM onto the bus. The LEDs show this as 11001000 (0xC8).

The Data Register has grown quite a bit more complicated. The chips with wires going to the bus are 74LS244 octal tri-state buffers. These separately connect/disconnect the inputs (blue) and outputs (yellow) of the counters to/from the data bus. If I were using CMOS chips, I would leave the inputs connected and only switch the outputs. But with TTL, inputs draw non-trivial current and I don't want to load the bus any more than necessary; breadboards already have a hard enough time delivering power.

The 193s have the same jumper wire colors for clear, load, down, and up as the data pointer but are connected directly to the power rails rather than through buttons. At this point I'm more concerned with moving data between RAM and the register. I can do that in this shot by moving the blue jumper to ground on the data register (input from bus), then momentarily bringing the orange jumper to ground (load).

Once the value is loaded into the register it can be modified with the up/down jumpers (albeit with tons of bounce). Then I can load it back into RAM by turning off the output from RAM (set its blue jumper high), enabling output from the data register (set its yellow pin low), and momentarily set the RAM's load pin low.

Next post will demonstrate some of this in action.

Part 1 (first) - Part 2 (prev) - Part 4 (next)

TTL Brainfuck Computer Part 2 - First steps

Part 1 (prev) - Part 3 (next)

The most basic piece of a breadboard computer is, of course, the breadboards. I found some Elegoo brand 3-packs on Amazon with primarily positive reviews for less than $10 and snagged a couple, along with some other Elegoo kits which each came with one breadboard.

I was not impressed at all with their quality. The clips were misaligned so that inserting leads was tedious-to-impossible. Their own brand power modules, which have a DC jack and plug into the power rails on a breadboard, would not fit without some extreme jiggling & pin bending.

I left a one-star review and they sent me replacements hoping I'd reconsider. At first they seemed much better than the original set. But while they didn't have the same frequency of issues, they still had problems. For one thing, the DIP switches I got will not stay in the holes at all. Tactile switches are similarly hard to keep in. By comparison, a breadboard that came with an electronics kit years ago holds onto these with enough force that they were more difficult to remove than insert.

I ordered some better ones which should be here this week, but these ones work just well enough that I couldn't resist starting. Here is an initial layout:



All but two of the breadboards had their "top" power rail sliced off (the slicing is just through the double-sided tape; they're otherwise joined by plastic tabs). The boards and power rails were joined together in two chunks each. I cut some pieces of hookup wire to connect the power & data buses together.

The clock is a 555 timer. The second 555 is for de-bouncing the manual clock button. I'm planning to use a different design that only needs a single 555, but I need a SPDT switch, not just an OFF-(ON).

Data Pointer and Data Register/ALU are made of Binary up/down counters (74LS193). This naturally represents the fundamental Brainfuck operations of +, -, >, and <. The Data Pointer pictured here has only 3 of the 4 chips needed to address 32 K of RAM. A handful more of these chips should be arriving this week.

A + instruction will cause the Data Register to increment. A - will cause it to decrement. A > will cause the Data Pointer to increment. A < will cause it to decrement. Values will be transferred to/from RAM whenever necessary.

Stack Pointer is also made of 193s to handle Brainfuck's [ and ] instructions. The location to jump to will be stored when entering the loop. An alternative design would be to keep a depth counter and decrement PC until depth goes down, but looping should be constant time for remotely reasonable performance.

The Program Pointer also uses 193s; It never needs to count down, but the other binary counters in the kit are ripple carry and can't be loaded directly with data. It needs to be able to load a program counter location from the Stack Pointer.

Data and Stack RAM are made of 32 KB ram chips (CY7C199-35PC). Stack needs 2 of them to handle the address width of the Data RAM. The two chips will have address lines in common, so it acts as a single 32 K x 16-bit memory.

The microcode stepper is a J/K flip flop to toggle between micro-instruction steps.

The Program & Microcode ROMs are 32 KB EEPROMs (X28C256P-15). This is massive overkill for the Microcode. I shouldn't need more than 8 bits per instruction and Brainfuck only has 8 instructions. I may end up doing the microcode with discrete logic gates just for the challenge.

Part 1 (prev) - Part 3 (next)

TTL Brainfuck Computer Part 1 - Intro

Part 2

A couple months ago I stumbled across Ben Eater's series building a breadboard computer out of TTL chips. I've had the idea in the back of my mind to do something like this for a while now, but Ben's series has kicked a lot of people over the edge and it's turning into a bit of a trend.

I've always had a soft spot for Brainfuck (and more generally, esolangs and obfuscated code). Way back in ought 6, I wrote an obfuscated Brainfuck interpreter to use as my e-mail signature (the yin-yang light bulb was my personal logo before Gnomes took over my identity):

#include      <iostream>       //  //    _            |  |
#include       <fstream>      //| //|  // \\        \  __  /
#include       <cstring>     //||//|| //  //       __ /o)\ __
#define S          32768    // |// || \\_//RLANDO     \(o/
#define b        ;break;   //  |/  ||ATTHEW    2006    ZZ
#define c(x,y)  case x:y  //==================================
char a[2*S],*m=a,*p=a+S,*r=p,o; void i(int n=0){char*l=p;while
(p<r){switch(*p++){c(43,++*m)b c(45, --*m)b c(62,++m)b c(60,--
m)b c(46,std::cout.put(*m))b c(44, *m=std::cin.get(o)?o:*m)b c
(91,if(*m)i(n+1);else for(o= 1;o&&p<r;++p){o+=*p==91;o-=*p==93
;})b c(93,if(*m)p=l; else return;)}}}int main(int _, char**f){
memset(a,0,2*S);std::ifstream z(f[1]); while(z.get(*r++));i();
return 0;} //BF interpreter. No err chk. 32k mem, 32k program.

Someone who knows me well enough probably could've predicted my urge to make a hardware Brainfuck computer after seeing Ben's series.

From the beginning, I had some guiding principles for the design:

  • Provide enough storage for non-trivial programs - Minimum specs matching my Brainfuck signature: 32 K instructions, 32 K data.
  • One-to-one correspondence between Brainfuck commands and CPU instructions - There is merely an encoding difference
  • Constant time execution of each instruction - It should never take more than 3 cycles to execute any instruction
  • Minimal number of execution steps - If an instruction can be executed in one cycle, it should be
The RAM needs are behind most of my departures from Ben's design. He's using a pair 74189s (or equivalent) which are 16 x 4 bit each, for a total of 16 bytes of RAM. His computer uses a Von Neumann architecture, so his RAM is used for both code and data, and all data transfers happen over a single bus. This makes his computer much closer in design to the CPUs inside desktop computers, smartphones, etc.

Brainfuck programs are extremely inefficient in code size, and fairly inefficient in memory usage. Only the most trivial programs would fit in 16 bytes (nothing close to printing the Fibonacci sequence). Since I'm targeting minimal clock cycles, a Harvard architecture makes more sense, where data and instructions are transferred on separate buses. Since Brainfuck programs are so inefficient in code size, it would be extremely tedious to have to enter the program every time the system powers on. I decided to use EEPROMs for the program memory.

I spent some time playing with logisim-evolution, a digital circuit designer/simulator to get a rough idea of the implementation. By using RAM with asynchronous outputs (output changes immediately when the address changes) and separate inputs, I was able to make a design that executed one instruction per cycle.

Then I started looking at hardware. Jameco sells a kit with 10 or 20 each of 35 different 74LS chips, which I believe is the same kit Ben used. Except for the RAM and ROM, this kit has pretty much everything I needed. The most important parts are the binary up/down counters (74LS193) since half of all Brainfuck operations involve either incrementing or decrementing a number (either the location in memory or the data in memory). They also had a suitable EEPROM. So that side of things is fine, but I still needed RAM.

Even if I used every flip flop & latch in the kit, I would still only have probably a hundred or so bytes of RAM, so I went looking for SRAM chips with 15+ address lines. Unfortunately, the only asynchronous SRAM chips available with separate input & output lines are fully dual port, meaning both sets of I/O lines can act as input or output. This makes them much more complicated in design and the cost for a 32KB chip is north of $40. On top of the cost, they're all surface mount devices (BGA, QFP, etc), so I'd have to solder them onto a break-out board. I've never done surface mount soldering, and there's no way I'm going to practice on a $40 chip.

So I decided to scale back my ambitions and go for a 2-cycle design using single port RAM. I was able to get ten of CY7C199-35PC for half the price of a single dual-port.

In the next post, I'll show the initial breadboard layout and give an overview of the design of the computer.

Part 2

Tuesday, November 15, 2016

Third Degree Racism

I think we do a terrible disservice when we slap labels on people for "who they are" rather than "what they've done." We see a Trump supporter with "Put the white back in the white house," we see Trump's tacit approval, and we see another person vote for Trump. That person must "be a racist". Not "they're acting in a racist way," not "they're tacitly supporting racism." Racism is part of the person's nature, worthy of shame and ridicule simply because they voted for Trump. Maybe in a technical sense it's true. The word "racism" has a subtler meaning among academics and the socially conscious. But most people don't have this understanding of the word by default. When you call someone a racist that implies, to them and to others, that you think they are as worthy of contempt as the people assaulting minorities.

We only hold people absolutely culpable when they knowingly, intentionally, and willfully kill someone. With 1st degree murder, there has to be evidence that the killing was intended while the killer had a cool head. These are the people who kill for pleasure or personal gain.

In 2nd degree murder, the willfulness and knowing are called into question. Drug use, fits of rage, etc. disconnect people from their better judgement and cause them to act in ways that go directly against their own will. They are culpable for allowing themselves to become impaired. We blame them for the murder, but we recognize that it's not on the same level as someone who spends a week plotting to kill someone.

3rd degree murder (manslaughter) generally means there was no intention or willfulness to kill, but a reasonable person in the same shoes would have been able to prevent it (that our legal system is built so heavily on what a "reasonable" person would do is a whole other can of worms).

Then there are other classifications for killing that aren't even called murder. They acknowledge that the killer is responsible for the death, but that there are other factors that mitigate both fault and responsibility. They may only be subject to civil penalties rather than criminal.

I wish we used this kind of categorization in our interactions with people. Trump voters are indeed racist, but to varying degrees. Varying enough that if we could measure people's Racism Quotient, there would surely be a significant overlap between Clinton's supporters and Trump's. The only way we will be able to win over the people we need is if we don't alienate them. The best way to alienate them is to display that their actions are unforgivable and forever label them as "racists", "white supremacists", etc.

Thursday, November 10, 2016

A Romantic Ending

In order to see what Trump offers as beneficial, you need to have confidence in "the American dream." The ability to have that confidence, to truly believe that anyone can reach any level of success just by working hard enough with no consideration given to chance or starting conditions, is a privilege. It's not about how financial successful you are now, but how in control of your own fate you believe yourself to be.

People who grow up in parts of America or otherwise under conditions where they can't believe in that dream, where it's obvious that the "others" and "have-nots" are being forced to remain "others" and "have-nots," and where your starting conditions all but guarantee the path your life will take, they don't have the luxury of soothing their insecurities with the notion that everything will be OK if they just work hard enough.

But this isn't necessarily about Trump in particular or conservatives in general. The mentality that all you have to do to succeed is to put your mind & body to work in just the right way, to put your own interests first with the sincere belief that the result will be prosperity for everyone, to go through life actively making yourself oblivious to the day-to-day sufferings of the people just "over the hill" but displaying self-righteousness for your minuscule efforts to fix global, systemic problems that need an entirely different way of operating our economy...

These descriptions fit equally well for a lot of the left wing new agey types. The folks who wrote-in for Sanders rather than voting for Clinton to make a statement. The ones who deny vaccines for their children and yell at my wife to stay inside from the chemtrails when all she wanted to do was admire a beautiful sunset. The ones who assign orders of magnitude more value to instinct than to objective reality (especially when it comes to children).

America idolizes Romanticism (the philosophy, not the courtship rituals). When you start with the fundamental world views of conservatism (in-dependence is the path to prosperity, things are fine the way they are) and liberalism (inter-dependence is the path to prosperity, we should always be trying to change), Romanticism distorts them in ways that emphasize the differences and make it harder to reach a shared understanding.

Romanticism sets up expectations that are doomed to fail for the vast majority of people, much like the promises of multilevel marketing schemes (exponentials are a bitch). Also like MLM, the most insidious part of these expectations is the idea that you only have yourself to blame for failure. If only you had sold more, if only you worked faster, if only you could find the right words, if only you weren't such a loser. This clearly has a depressing effect on the overall mood of the country.



From an anthropological perspective, it sucks that entire ways of life are lost to the ages. From a personal perspective, it sucks more to have the world as you know it crumble around you, and even more when the folks from distant lands who control most of the water and all international commerce are making all the rules for you. And describe you "from an anthropological perspective."

But this nostalgia and attachment to the present/past is doing all manner of measurable harm up to and including killing people. Conservatism demands that we maintain bigotry. That we perceive all suggestions to change as threats (unless they roll back previous change). That the way things were is better than the way things are or the way things seem to be headed. That the world is too complicated for us to make any rational choices on a national/global level. Liberalism is much more open to change, but is vulnerable to similar failings from a different vantage point.

We need to have a sit down with our egos, take a nice big dose of reality, and realize that there's no way we're going to get through this without working together. Reality, nature, God, whatever you want to call it, has set up a game with all kinds of traps and pitfalls, Pandora's boxes, great rewards and great suffering. Contrary to much received "wisdom", that game's rules are consistent and generally predictable. By asking the right questions we can learn how the universe behaves in ways that Romantics believe we can't. By testing our assumptions and calling our beliefs into question, we can make changes that produce a measurable improvement to everyone's quality of life (not just the people with the cities). There's no way we can do that alone; we are too imperfect.

Us vs. The World gives us much better odds than Us vs. Each Other vs. The World. But you can't just sit there and expect everything to be OK without accepting change and relying on others.

Wednesday, November 9, 2016

Elephants, Donkeys, and Voting, Oh My!

A lot of Democratic voters (read: much of my Facebook feed) have expressed extreme surprise, if not genuine shock, at Trump's win. I wonder if their level of surprise is correlated with how they voted in the primaries. Much of Sanders' support came from people trying to serve the same need as the people who support Trump: the need not to feel consistently ignored by the people in power. My hypothesis is that Sanders supporters who voted for Clinton have no small helping of "told you so" to mitigate their "OMFGWTFBBQ!!!!111"

To be clear, the level of sadness and rage is completely understood, and I share it to the extent that a privileged, straight, white, cis male can. However, I can't say it came as a surprise.

Just before the election, Nate Silver seemed to be defending FiveThirtyEight's suggestion that Trump had a significant chance of winning. My trust in the quants grows stronger.

It's ironic and sad that so many people thought Trump would be the end of the Republican party, when it seems to be the exact opposite. But hopefully the level of success of both Sanders and Trump will be a wake-up call to everyone working to keep the status quo.

Speaking of status quo, there's the Electoral College. I know a lot of people will feel betrayed by the system because Clinton seems to have won more popular votes (albeit narrowly). On the one hand, in a first-past-the-post, winner-take-all system that is inevitably reduced to 1 or 2 choices, we really are being failed by the system. But the problem isn't the electoral college itself. I actually think the electoral college is doing exactly what it's designed to do: limit the influence of states that happen to have a disproportionate share of the population due to the chaotic interactions of geography, economics, and time.

The simple fact is that much of the country wants something that Clinton couldn't offer but Trump is willing to promise. National frustration with DC and Wall Street is at an all time high. Confused as we might be wondering why people believe he'll actually improve things for them, he definitely offers "something different."

But the problem isn't the voters or the electoral college, it's the way we actually express our votes. There were several candidates besides Trump and Clinton who many people would've been happy to see as President, even if they ultimately voted for a major candidate. But the way we vote, where every person gets a single "Yes" to assign to a candidate, has been proven mathematically to lead to a two-party (or one-party) system over time, and to minimize voter satisfaction.

Wouldn't it be nice if instead we could say "I would be OK with these people being president, but not these ones"? Or even better: "I really like this lady, I'd be OK with that guy, but NO WAY do i want HIM in office." In a hypothetical race, Bernie could still be on the ticket without taking votes from Clinton, people could vote for Stein, Johnson, or that guy from Utah without feeling like they wasted their vote. Even write-in candidates would have a chance of winning, if they reached a minimum share of the vote.

This kind of voting, known in various forms as approval voting, range voting, score voting, is in use at various levels of government all over the US and the world. The cool thing is that there is nothing in the constitution that dictates how popular votes are counted, only that the states pick electors for the electoral college based on the results. That means this change can happen in a grass-roots way, much like marijuana legalization (see what I did there?). We don't even need a constitutional amendment for this to work.

If you can't readily imagine the kind of difference this would make or are curious to learn more, have a look at http://rangevoting.org/. There is everything from a simple high level overview down to thoroughly sourced arguments and original research. As I mentioned earlier, our current voting system has been shown to lead to a minimum of voter satisfaction. Not just suboptimal; one yes vote per person, first past the post, winner take all is worse than every other democratic voting system as far as producing outcomes that satisfy the most people. Even something as simple as changing it to "Yes/No" for each candidate makes a 'UGE difference.

Please consider bringing this up with your local, state, and national representatives. It's an achievable goal that would dramatically improve how Americans feel about their ability to be heard through their votes.