I have 5 articles waiting to finish and publish, most of them are touching theoretcal approach of the Nexi microcomputer. But I am too impatient, I want to run something! I have decided to make a smoke test of my chosen m68k. This is a starting point, most of the work will be a development of this simple test.
Couple of weeks took me to run m68k core for the first time. I have decided to use ao68000 core by Aleksander Osman. It is written in verilog with Wishbone b.3 interface (written as separate module, so it would be quite easy to change it to original m68k interface), finished (most projects aren’t fully functional). Disadvantages are not exact timing of instruction (I don’t care) and usage of wishbone bus (I’m not planning to make any application with physical IC, so, also, I don’t care).
AO68000 was using ram Altera’s megafunction as a storage for microcode and A and D registers, so it was impossible to run it on simulation. I have rewritten this piece of code with standard RAM implementation. With success!
Next, I have written simple testbench, to connect ao68k with wishbone based RAM module. The catch was with address lines connection. AO68k is using wishbone’s SEL bus, which indicates what part of dat_o signals are expected to have valid data. For example, if microprocessor want’s to read 1 byte of data it changes the state of sel[3:0] to 0b0001. If microprocessor want’s to read whole 32 bits of data it changes the state of sel[3:0] to 0b1111. AO68000 have 32 bit address bus, 32 bit data bus and 8bit granularity.
Because of the fact, my ram module’s size is determined by address bus width, and I wan’t to have 1M of RAM, I have defined 32 bit adddress wire, connect [32:2] lines with ao68k, and [19:0] to ram module, assigning the 2 least significant bits with zeroes.
Next step was to create a memory dump with valid exception table and code. M68000 expects to have Exception table at the beggining of the memory address space.
/* exception vector table */
The code is pretty straightforward. M68000 requires to have exception vector table at offset 0x0. This is a major issue when designing your board, because it also requires to have RAM memory starting at 0x0, which is uninitialized after a reset. M68010 has Vector Base Register. It’s value is added to the offset of exception to compute the absolute address of exception function. At reset time, the value to VBR is 0x0, so you also have to have initial exception table at 0x0. But we don’t have to worry about that now. First two entries have 32 bit, where all other have 16 bit entries. Not all entres all included.
The actual code starts at 0x100. We make some random moves, then loop again to the label at 0x100. Nothing more. This piece of code helps me to investigate m68k assembly, by playing with it, and watching, how it is behaving in gtkwave.
Compilation is a bit tricky. I use m68k-unknown-elf compiler, created with crosstool-ng. raw2vnem.py is a script that converts 32-bit hex input into vmem output, for reading by readmemh.
$(CROSS_COMPILE)-as -m68000 -o loop1.elf loop1.S
$(CROSS_COMPILE)-objcopy -O binary loop1.elf loop1.bin
dd if=/dev/zero of=loop1.raw bs=512 count=1
dd if=loop1.bin of=loop1.raw conv=notrunc
xxd -p -c 4 loop1.raw | ../tools/raw2vmem.py > m68k_initial_ram.vmem
Let’s see how does disassembled code look like. As you can see, rasm2 is using U2 encoding instead on unsigned one.
$ xxd -p -seek 0x100 sw/loop1.bin | rasm2 -a m68k -b 16 -D -
0x00000000 2 4e71 nop
0x00000002 6 203ca5a5a5a5 move.l -0x5a5a5a5b,d0
0x00000008 4 323cbeef move.w -0x4111,d1
0x0000000c 2 d240 add.w d0,d1
0x0000000e 10 23fc5a5a5a5a00000000 move.l 0x5a5a5a5a,0.l
0x00000018 4 143c00de move.b -0x22,d2
0x0000001c 4 4efaffe2 jmp 0(pc)
The final step is to run it all, and analyse the waveform. Seems like everything is working fine, the code forces the cpu to jump from 0x0000011c up to 0x00000100. The additional 0x0000011e and 0x00000120 is probably caused by prefetcher. The code is available at nexi github repository.
My current (not organized) todo list contains:
- create high level design of the project
- analysis of ao68000 internals
- rewrite its microcode generator
- create/obtain table of differencies between 68000, 68010 and so on
- first draft of cache module
- run above code with added uart ip core in some FPGA devboard. Then, write bootloader for it.
- toolchain research (crosstool’s gcc, llvm + clang, ready-to-use toolchains etc)
- run ucLinux on the core