Category Archives: Uncategorized

Designing an instruction set for a stack machine

omap

I’ve spent a lot of time hashing out the instruction set for the CPU I’m designing. My first shot at it didn’t work out too well for a number of reasons. For one, I originally tried to keep the number of opcodes with immediates down to a bare minimum.

Originally the only instruction I had with an immediate was push. To do conditional branches, I had an instruction called ‘istrue’ which would execute the next instruction if true and if false it would skip over it. That only left one instruction for the branch, not enough space to setup an address on the stack easily. There were only two ways to do it, write a really convoluted procedure which made loops practically impossible to understand or abuse the address stack and jump indirectly via the return instruction. The indirect jump via return method required setup in advance and careful attention to tear it back down if the condition was false or you end up accumulating garbage on the address stack or inadvertently jump back into the loop somewhere else down the line.

I’ve gone from around 30 instructions to 51. 15 instructions now have an immediate. I added a few instructions to make it easier to deal with variables in memory so there doesn’t have to be as much stack shuffling. I got rid of the ‘istrue’ conditional branch and now have seperate call and jmp instructions that can take values either off the stack or as an immediate with branching based on a boolean sitting on the data stack.

You can now store with or without an immediate either byte or word sized values. Also added instructions for incrementing and decrementing memory directly.

The new opcode map is here on the left. The stack columns have an In and Out section and each section have ‘ia,ib,ic’ and ‘oa,ob,oc’ fields. The ia-c fields are the inputs and the oa-c fields are the outputs. A,B, and C refer to elements on the stack with A being the top of the stack, B being below and so on. The code field is the byte representing the opcode. Fields i0-i5 are the bytes that make up the immediate associated with the opcode.

Fields are marked either a, d, or b which represent an address, data or a boolean. The in fileds represent what is being taken off of the stack and the out fields represent what is being placed onto the stack. For instance, drop takes an item off of the stack and leaves nothing on the stack after it executes. dup takes one item off of the data stack and leaves two identical items on the stack. a2d takes an item off of the address stack and leaves it on the data stack. ret takes an item off of the address stack and leaves nothing. (it assigns that item to the instruction pointer) fetch takes an item (address) off of the data stack and leaves an item on the datastack (the word at that address). calli doesn’t take any value off either stack, it has an immediate (a procedure address) and leaves an item on the address stack (the return address, which is IP + next opcode address).

Overall, this has been a lot more difficult to design than the VM’s I’ve written in the past. In those cases everything was 32bit, since none of the hardware was real I didn’t need to worry about things like reading and writing to different widths. (SFR mapped devices can be triggered on reads and writes). Communicating with the VM was done though mapped memory spaces and code complexity wasn’t much of an issue since most of the code was generated from python programs. Debugging with the VM was easy, it won’t be on the FPGA.

It’s starting to crystallize into something that could be useful. I’ll probably have to add a few more opcodes, change some others, but I think it’s going in the right direction.

More unhappy capacitors

DSC_0338

 

My power supply started emitting smoke today. Opened it up and found some bulging capacitors and greasy residue on the top of the chassis directly underneath them. Two 4700uF @ 16v caps. I don’t have any of those values on hand, so I had to use a pile of different ones to do the repair. Fortunately the PCB is resting on a set of metal standoffs so there was adequate room to solder some in underneath.

DSC_0342DSC_0340

I put everything back together and it works fine now. I had to adjust two pots for the variable +- 15vdc outputs. The +5v and -5v were spot on. The AC 6v out measures 7v and the AC 12v out measures 13.5v. Nothing I can do about that, those lines come directly out of the transformer.

 

Writing an assembler

I have a rough assembler written for the CPU I’m designing. Enough so far to convert simple programs such as :

shoved 12 shoved 12 add

Into:

14 00 0c 14 00 0c 00

This will make generating code for testing the instruction fetch / decode unit a lot more convenient. I’m also using a python module titled ‘IntelHex’. Quartus II requires Intel Hex format or a proprietary Altera format for ROM and memory initialization files. This python module makes it easy to generate  hex files. You can find it here: https://pypi.python.org/pypi/IntelHex/1.1 . I’m documenting my assembler at this page: http://www.dillo.us/wiki/projects/doku.php?id=fpga_stack_machine_assembler

 

Implementing a CPU with verilog

procmap

So far I have a number of device modules put together and wired up on a bus. I’ve also implemented a push down stack as well. I’m getting close towards my goal of putting together a stack based CPU in verilog. The next module I’m going to write will be an instruction fetch / decode block. From there I should be able to start fleshing out some of the opcodes and get it running some code. I still haven’t decided what I want to do regarding interrupts or whether or not I want to support relative jumps. I’ve also come to the conclusion that my original requirement of three or less clocks per machine cycle isn’t going to be feasible for my first design. I’ll be lucky if I can get it down to three with the opcodes that have no immediate.

It’s a 16 bit machine with a 32 bit address bus, 32 instructions and two push down stacks. I’ve started putting together an overview here: http://www.dillo.us/wiki/projects/doku.php?id=fpga_stack_machine .I’m having a lot of fun putting it together and when I get it finished I should have built up enough experience to be able to do something with that USB phy.

W7S5YPWPGPAN

Driving an LCD shutter with a PIC 16F917

lcd_off lcd_on

This is a prototype I put together using an LCD shutter from a 5 dollar novelty keychain. I’m driving the shutter using the built in LCD segment driver on a PIC 16F917. The ultimate goal of this is to investigate the feasibility of adding stereoscopic support to my graphics engine by triggering the LCD with a photo sensor in the corner of the screen. Every even frame would have a light square in the corner and a black square in the odd frames.

The switching response in the LCD seems pretty poor. In the video below I’m strobing it ~18Hz. The red LED on the bread board is switched on when the LCD is dark. In this test the LED shines right through when it should be blocked. I don’t know whether or not the issue is with how the shutter is being driven or if it’s a response time issue. I’ll have to do more testing to figure that out. I don’t have time to move forward with this so I’m going to have to shelve it for now…

Memory stuff with verilog

I’m working on a LIFO module for the CPU I’m designing and was wondering whether or not I should use the megafunction for a ram block or just use an array of  regs. I went with an array of regs because that’s simpler. I expected it to just create a pile of FFs but the compiler used some of the on chip SRAM instead. Cool. I’d rather use of some of the M9K blocks than chew up a bunch of LEs  for that.

inferred_ram

Unhappy capacitors

My 21″ Samsung 204T monitor has been acting up for over a year. On power up it would flicker for a minute or two and eventually even out. This evening it finally died. I popped it open and found two bulging capacitors:

The two bad caps were each 820uF, wired in parallel. I didn’t have any of that size in my parts drawer, so I used a 1000uF, 470uF and 220uF. There was an unused spot for a capacitor next to the two that were bad, so I used that for my third capacitor. I drilled the holes a little wider so I could have room to fit some heat shrink tubing on that third capacitor where it went through the board. Then I soldered in parallel with the rest:

I put everything back together and the monitor came right up without delay and no flicker. The monitor is about 8 years old, maybe I’ll get another 8 years out of it.