Showing posts with label retro computing. Show all posts
Showing posts with label retro computing. Show all posts

Monday, November 1, 2021

Handheld RC2014 System (RetroChallenge (sorta))

One of the great things about making stuff is that you can make stuff that doesn't yet, or shouldn't exist.  

I honestly didn't get anything done on my RC2014 projects for RetroChallenge this year, other than an idea, and some 3D printed stuff within the final few days of the month.

I've had it in my head for a while to make a gameboy formfactor RasPi system for a while now, even though I already have a portable Pi emulation system in my Atari Lynx enclosure.  So I found a model for the "super retropipod" enclosure on Thingiverse and printed it out, and ordered and then modified a 3.5" lcd and shoved it all into the case.


I decided i didn't want to make a PCB or hack up a perfboard to support tact switches, and I had a bunch of largeish 12mm tact switches, so I modeled and 3d printed mounting boards for those too.


Then I had an awesome-horrible idea.  I would mount a RC2014 inside the enclosure as well!  If I managed to make the enclosure a little thicker (about 1cm) I could easily fit a RC2014 mini or micro inside the case along with the pi and all of its fun stuff.  I could even probably also fit in the TMS9918A video card piggybacked onto it inside the enclosure.  So I modeled and printed out the thickness extension too!

Long story short, I have the beginnings of my ultimate multipurpose Pi/RC2014/Llichen-80 handheld!  And she's a chonky beast too!

I modeled and printed a piece to sandwich between the layers of the "pi-boy" enclosure I printed, and added a space for a nice switch for power on the side.  I still need to wire it all up, but I'm on my way to having this thing be AWESOME!  

Although I still want to make a "tall-boy" at some point... take two GB DMG enclosures, and extend the screen space to be taller, and put in a rotated, vertical monitor in the space there.  eg, use a 4" or 5" lcd in portrait instead of a 3.5" in landscape...



Next actions on this project:

  • Wire up the buttons to the GPIO header
  • Wire up the LED on the front panel to the GPIO header
  • figure out a power solution for the system (batteries, recharging, etc)
  • Mounting solution for RC2014 inside the enclosure without it moving around
  • Make a 2-board backplane for the RC2014 so I can also have the TMS board internally
  • Wire the TMS to the monitor too, and figure out a quick way to switch inputs... perhaps two NC momentary buttons that disconnect the monitor from each of the two inputs, so it will auto-switch to the other input. (or short the input to ground via 75Ω resistor?)
Links:

Saturday, November 9, 2019

RC2019-10 - A102 project - The end of the month of hacking



The short version is that I was super productive on these projects this past month.  I didn't complete it, but I never realistically thought I would be able to.  I lost a week's worth of time, or so, prepping our yearly Halloween Hack (blog post soon)... not to mention losing some time to work on building my Lego Saab 900... (blog post soon too).
One thing I will say, is that by combining the projects together, I tricked my brain into quite effectively "being okay with" working on one project or another, by them all being part of the same project.  So I would say that the month was quite successful.


So Anyway, I'm going to first go through a bunch of goals for the month, for the RC challenge, and in general, and briefly discuss my progress on them at a meta-level.  Then I'll get more into details about the actual work.

Overview and goals


Raspberry Pi / Emulation

I wanted to get the Pi 3 configured and booting right into an emulated  Amiga/Amibian environment.  I got the pi configured with standard raspian instead of Amibian, since I wanted this to be more of a general use machine.  It'd be nice to be able to use it for firmware development of the LL530 as well as the machine that it's targeted for.

So the target changed on this, but it is complete for now.

LL530 Development

I wanted to have the LL530 (USB Interface to Amiga serial keyboards, Amiga/Atari controllers and mice) fully finished.  Although I did not finish the firmware this month, I got more done on the project this month than I had in the past 6 months.  However, I was able to test the DIN pinout to discover that it's backwards, so I need to rev the board for those...

I didn't fully succeed, but I was successful.... if that makes any sense.

RC2014 Integration

I wanted to have an RC2014 Z80 computer built in as well, that I can connect to via serial port, for doing RC dev work without an emulator.  This aspect sadly got the least amount of attention.  I have an RC2014 mini installed, connected to the serial port on the Pi 3.  I've rewired the connection twice now, and I still cannot get it to connect using this wiring.

I spent time focusing on the other aspects.  So... 25% success.

Integration / Battery / Monitor / Enclosure

Most of the effort this past month was in this area.  I wanted to have the entire thing as a finished unit; to be able to be brought to a coffee shop, pull it out, turn it on and use it wirelessly. I can do all of these things right now with it.

So I would say this aspect was completely successful... although It does need improvements, particularly with the screen.


Installing The Linux

I started with a base Raspian image from their site.  I had the Pi hooked up to a HDMI monitor with USB keyboard and mouse.  After using Balena Etcher to get the image onto an SD card, I booted the  machine up.  I went through the basic setup, and updates.

I launched raspi-config from a terminal window, and went through to  enable ssh, i2c, and serial.

Next I installed some useful software packages:

apt-get install screen fs-uae-launcher stella

I made sure that serial was enabled  in /boot/config.txt,

enable_uart=1

I use screen as my quick and dirty way to connect to the RC2014 which is wired up to the uart on the raspi per the diagram above.  The reset line is wired to GPIO 4, so i use this shell script to "hit the reset button":

#!/usr/bin/python

import RPi.GPIO as GPIO
import time

print "Resetting the RC2014."

# setup GPIO4 as an output
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(4,GPIO.OUT)

# send LOW (reset) for 1 second, then restore HIGH (normal run)
GPIO.output(4,GPIO.LOW)
time.sleep(1)
GPIO.output(4,GPIO.HIGH)

print "Done."
# return to high-z state
GPIO.setup(4,GPIO.IN)

The Red and Green LEDs are wired to GPIO18 and GPIO12, and I can run this script to do a nice fadey display on them:

#!/usr/bin/python

import RPi.GPIO as GPIO
import time

red = 18
green = 12

GPIO.setmode(GPIO.BCM)
GPIO.setup(red,GPIO.OUT)
GPIO.setup(green,GPIO.OUT)

r = GPIO.PWM(red, 100)  # channel=12 frequency=50Hz
g = GPIO.PWM(green, 100)  # channel=12 frequency=50Hz
r.start(0)
g.start(1)
try:
while 1:
for dc in range(0, 101, 5):
r.ChangeDutyCycle(dc)
g.ChangeDutyCycle(100-dc)
time.sleep(0.01)

r.ChangeDutyCycle( 100 )
g.ChangeDutyCycle( 0 )
time.sleep( 1 )

for dc in range(100, -1, -5):
r.ChangeDutyCycle(dc)
g.ChangeDutyCycle(100-dc)
time.sleep(0.01)

r.ChangeDutyCycle( 0 )
g.ChangeDutyCycle( 100 )
time.sleep( 1 )

except KeyboardInterrupt:
pass
r.stop()
g.stop()
GPIO.cleanup()

I may rewire these, or wire up additional LEDs to the ones specified with the Amibian/UAE led indicators, which are defined as GPIO4 for activity, GPIO16 for "Power", and GPIO16 for a clean shutdown button.

LCD Monitor


For a monitor, I'm using a $10 3.5" composite monitor.  I had to do a few things to get it to work however.

I had to hack the power input so that it would run off of 5v.  These are made to be used in cars, so they expect 12v of power.  At the time I did this, there were examples of doing this modification on
other displays, but not this model.  I powered it up using 12v, then probed the outputs in the power supply section for a 5v rail... and I soldered a 5V input there.

Once I had done this, I connected it to the 5v power in the enclosure, and hooked up the video input from the composite output on the Pi 3.

One snag I hit though, is that it wouldn't work right, It would flash on when the Pi booted, but it wouldn't show the desktop. Testing the Pi with HDMI or a known working composite input worked just fine though.

I was trying all sorts of things, and eventually decided upon trying PAL  video modes instead of NTSC, and that worked.  I spent some time tweaking the overscan settings as well, to stretch the screen to fit.  I also noticed that the contrast viewing range was substantially better on the top side of the display, so I ended up mounting it in the enclosure upside down, and I flip the video in the pi's config too.

So the changes that all this amounts to for /boot/config.txt are:

disable_overscan=1
display_rotate=2

overscan_left=0
overscan_right=0
overscan_top=5
overscan_bottom=5

sdtv_mode=2
sdtv_disable_colourburst=0

framebuffer_width=320
framebuffer_height=288

Although, as you can see from the screenshot above, it's basically unreadable.  So I was able to get it to work, but any future development on this will need to be with a different display.  Something with at least 480 rows, so that Amiga emulation can be reasonable on it.

Combining it all, and the Future...

I spent a few evenings rewiring that keyboard which mostly works really well.  I'm using a 5000mAh battery and get an undetermined-but-better-than-my-old-iBook amount of time with it.

The display is garbage.  I'm currently looking into replacing it with an HDMI-based 4" Waveshare IPS display with an 800x480 resolution for about $40.  Surely that will require moving around hardware inside of this enclosure, and since the display is meant to piggyback on the Pi, I will lose my integration board.

Obviously, I'll need to install the Amiga emulator, Tandy 102 emulator, my Model-T-Shell, and the Arduino IDE so that I can continue development on the LL530

In short, I'm super happy with where things are now, it just needs some tweaks to get it to be usable as a primary system. :D

Wednesday, October 2, 2019

RC2019-10 - The Globbing Of The Projects... Globjects?



Hey.  Long time no post.  How y'all doing?  I'm still here. I've gotten a lot of small things done over the past half year, and a lot of things almost done as well... and some long-standing projects not done too.  So, I've been almost productive...  Anyway, I hope to try something different this month for the RetroChallenge RC2019-10...  Let me explain...

The main projects I've been trying to work on recently are:


LL530 USB interface for Amiga serial keyboards and controllers

I've been poking at it a little over time, and am really damn close to getting the proper firmware done for it, but I just haven't finished it.  Which is stupid because I can actually sell these things once I'm ready!  I have keyboard working for all but my A1000 keyboards, and I have joystick/mouse/paddle working... but not at the same time in a way that I'd be proud of.  I also will eventually need to rev the board to fix three layout issues; a power/ground short, lack of ICSP programming header, and lack of pull-up resistor for VCS paddle sampling.


Llichen-80 Computer (LL80)

Okay, so it's not really a whole other completely new computer... but it is a specific configuration of the RC2014 Z80 computer.  It started out this year as a whole lot of customizations to standard (but old, obsoleted) RC2014 boards to add bank switching, using the 8 bit parallel IO board (the one with all the LEDs and switches!).   Now, I reworked the idea so that I just use the standard "Switching ROM" board and the "64k RAM" board.  That simplifies the design; making it easier to get to the LL80 spec, since just using those two cards replaces two RAM boards, one ROM board, and one IO board... plus no modifications to any of the boards are necessary.

The other part of the LL80 computer is the "LLSuper" board.  This is an arduino-based supervisor of sorts that sits on the serial console port.  It acts as your usb-serial interface for when you use a desktop computer as a console.  This board used a CH376S USB Drive interface to access any flash drive as mass storage (it's a neat part.. like $2 for a board with a USB A port... it talks TTLRS232, SPI or parallel, and handles all of the disk switching, FAT filesystem etc. So there's very little overhead on a tiny ATmega micro.  I also have an I2C based clock chip board for this.  This sits between your console and the RC, and lets you have a kind of shell access to the disk from the console, as well as from the RC.  The RC side of things also got direct access to virtual disk image files with a sector-based interface, as well as direct fileio...

The next steps would have been to write a CPM BIOS and make the thing boot into that.

But I've come to realize that even the LLSuper board is unnecessary.  I can accomplish near-similar things using the standard  "Pi Serial Console" board.  If i use a RasPi Zero, and boot linux on it (or adapt the code in the PiGFX kernel, I can put in my serial-disk IO stuff, for cheaper, without needing to fab up my own board.  I started to mess around with this using my new RC2014 Micro, a Pi Zero, and a slight hack to attach the reset line of the RC to a GPIO of the Pi, so i can now reset the RC from the Pi.

I do have the protocol all worked out for the serial interface using unused ANSI escape codes, which are made for custom purposes like this.

A102 - Portable Emulated Amiga in a Tandy 102 shell

This is one i've wanted to work on since last year. I was trying to get it done before Rochester MakerFaire last November, but burned out on it.  It essentially is a project that joins together a bunch of parts... all of which I have:

  • Raspberry Pi 3, with Amibian... booting right into an emulated Amiga environment
  • Tandy 102 shell, rescued from some unrepairable 102's
  • Tandy 102 keyboard, also rescued (keys bind as they're pressed though)
  • Amiga 500 keyboard interface board, from a long-gone computer
  • My LL530 USB serial keyboard interface board
  • Amiga mouse
  • 3.5" composite LCD panel (new, $10 online!)
  • large Power Bank battery pack
This project entailed hacking the keyboard (removing the wiring/traces on the board) to convert the scan matrix to match an Amiga 500 keyboard.  This gets connected to the LL530, which is plugged into the Pi.  All of it gets jammed into the 102 shell, and becomes a portable computer. 

I waffled a bit on this... mainly because the keyboard stuff would be a chore.  I want to remove every key, and clean their travel tubes, to eliminate the keys binding.  Wiping out the traces and rewiring the board seems like it's going to be a tedious process... So i kept thinking that maybe I should make a cherry-mx switch based board to fit the keyboard space instead... and... yeah... i just kept going down that same path of "maybe i should do this other thing" instead... instead of actually moving forward on any of it.

I also pondered putting the entire Llichen 80 computer into this shell... which brings us to...

RC2019-10!

So that's where RC2019-10 comes in.  Why almost fail at three projects when I can almost fail at ONE project! Seems a lot more efficient!

The end result for this month will be to have a working portable laptop computer that runs Amibian (Linux), RC2014 (via serial connection to the Pi) and general Linuxy stuff.

Or, more granularly, here are the tasks as I see them now: (in no particular order)

  • Finish the Keyboard + Joystick/Mouse firmware for the LL530
  • remove the wires on the 102 keyboard PCB
  • clean the travel tubes on the keyboard
  • rewire the keyboard to match the Amiga's matrix
  • Wire the keyboard to the Amiga 500 interface board
  • Connect the RC2014 Micro via the Pi's serial interface pins
  • Additional buttons on the device to cleanly shut it all down
  • Have it all powered from a 5V/USB powerbank mounted internally
  • Serial-console textmode app for Linux that provides the beginnings of a backchannel to 
Stretch goals:
  • Full drive interface for the RC2014
  • CP/M BIOS for the RC2014 that uses the serial protocol
  • Fit the RC2014 Mini + 64k RAM + switching ROM + TMS9918A cards inside the case
  • Have the video switchable between the Pi and the TMS9918A video card

Not sure how far i'll get, but it globs together all of the recent projects in a way that I won't feel like I'm neglecting one project by working on the others... since they're all the same project now. :D

Thursday, March 21, 2019

Llichen-80 (Retrochallenge 2019-03 Update)

I had originally intended for any time I could devote this month to the 2019-03 Retro Challenge was going to be for a new version of my RC2014 Z80 computer emulator, adding support for the TMS9918A video display chip.  But my plans have changed.  With the recent advancements with The 8-bit Guy's "Commander X16" 6502 computer, I decided to start reviving a project I was considering for a while.  The great thing is that there's so many aspects to it that it's like a grab-bag of things to do.

The original idea was to sit down with a C64, floppy drive, monitor, joystick, mouse and reference books, and start with BASIC, writing a text editor, assembler, IDE, etc and work my way up to having a windowed operating system like GEOS with a few utilities and such.

Except now, the spec of the system is designed by me, and I'm building that too.... Which meshes in perfectly with my original intention to build a RC2014+TMS9918 emulator, which I can use for initial development, and kickstarting the boot rom onto it.

Hardware

I wanted some sort of related name for the project, so I was thinking Llama, TMS, which became Llitmus, like the PH sensitive dye.  I was gonna go with Llitmus-80 with the '80' because it uses a z80, but then once I read that the litmus was made from lichen, I just went with the name Llichen-80.

First, let's get into the Llichen-80 system specification.

  • RC2014 backplane/base system
  • 7.37 MHz clock speed
  • 32k RAM from 8000-FFFF
  • 8k BASIC ROM from 0000-1FFF (*)
  • 32k RAM from 0000-7FFF (*)
  • Digital IO board at port 00
  • TMS 9918A video board at port 10,11
  • ACIA Serial port at 80
  • ACIA Serial port 2 at C0 - connected to CH376S USB drive interface
So (*) Indicates something... there's an overlap of these two items. My existing design piggybacks bit 0 of the output from the digital board to select which of the two of these that memory READs come from.  That is to say that writing 0x00 to the digital out board will select ROM, and 0x01 will select RAM.  Writes to these locations always go to RAM.  So one way I can test this is:
  • Start up the computer
  • select ROM bank
  • Write a basic program to peek from the ROM and write to the RAM
  • select the RAM bank
  • Yank out the ROM board, and everything still works fine
10 OUT 0,0
20 FOR A=0 TO 8192
30 B = PEEK(A)
40 POKE( A, B)
50 NEXT A
60 OUT 0,1
RUN
This all works great!  One addition I made was to intercept the VCC to the RAM chip and have it also connected to some CR2032 batteries for a backup.  It's not perfect, but it works well enough for my system for now.  I also added a switch to force the use of the ROM, since sometimes the bank switching can get into a messed up state and you need to force reboot off of the ROM.

The other thing I created was a second ACIA serial port, essentially duplicating the circuit of the stock ACIA serial port, but changing it to look at ports C0 and C1 instead of 80 and 81.

The TMS could be configured for anywhere, for the most part, but the ACIA chip IO port mapping is messy so they consume essentially from 80 to FF.  I went with the SORD-M5 configuration of putting it at 10 and 11h.  Although there might be issues with this...

Anyway, more about these modifications and such at the end of the month.

Experiments 



I ended up reassembling my RC2014 system, and started working on testing out the configuration.  I Was able to write a few BASIC programs to output to the video chip and to a TV I had hooked up, as you can see in the photo above.  I was noticing some weirdness though. The LEDs on the IO board were flickering when I was doing writes to the TMS, so I may need to move the port around to another location. I think I'm gonna go with the MSX setting of 98 and 99h.

I also became very aware that I do not yet understand how to get the chip to do what I want.

Emulation


I was going to write the emulator using QT Creator for maximum portability, and also using the Z80 emulation core and frameworks I created for my existing RC2014 emulators.  But recently, after thinking about it for a little bit, I realizes that 90% or the emulator I need is already out there and already very well supported.  MSX.

There was really no need to get a whole video display system working with my existing emulator when I could start with an existing, debugged, well supported emulator, openMSX, and just create a new hardware profile for the RC2014 with my system's configuration... and with some changes to support my bank switching hardware and such.

I made a branch of openMSX on github to handle any/all of the changes I've made for it, which at the moment is just getting it to build on OSX/Darwin 10.14 correctly.

I also was messing around with my good old friend, the Texas Instruments TI-99/4A as it uses the TMS9918 chip. I figured that I could experiment around with how color and graphics look.  I'm not a fan of the TI's font, nor the MSX's font for that matter, but I figured it's a good platform to get reacquainted with the weirdness of the TMS and to see how this all might look in the future, perhaps.


This is of course just a screenshot from the impressive web-javascript TI emulator at js99er.net.

More as it develops...

Friday, September 28, 2018

More Laserdisc Stuff! A wild Pioneer CLD-V2400 appears!



I just picked up this Pioneer CLD-V2400 in full working order, and in excellent condition.  It was made in 1993, around the same vintage as my Pioneer CLD-S201... but with one major difference... a SERIAL PORT!


It's missing a couple of the more "industrial" commands that allow it to seek quickly (+/- 100 frames) without noticeable glitches/squelching.. so it's not ideal for laserdisc video games, which were crafted so that you could play a game non sequentially without seeing pauses as the disc seeks.  I guess it's able to move the head super quickly within the VBLANK section of the disk

I'm getting ahead of myself...



This thing has a DB-15 connector On the back for the RS-232 serial interface, which includes TTL Serial (0-5v) and RS-232 serial (+/- 12v).

Since I couldn't find my USB-Serial interface, I tried making a TTL cable, and connecting that via FTDI cable to my Mac... I wasn't able to get it to reliably work. I think it might be a that the FTDI/Mac combo couldn't do the 4800 baud rate or something.





Instead I made a DB15-DB9 Null modem cable, and decided to plug it into the 9 pin serial port on... something?

I had a hard time finding any of my machines with DB9 serial, but eventually remembered that my tiny Toshiba Libretto 50 has one! So yeah! Windows 98 and HyperTerminal it is... and it worked great!

Next, I went through the V2400/V2600 manual, (and the V4400 manual) to figure out some commands that I could do.

I had some experiments I wanted to do with using the "user area" of the on screen text of the player.




First of all, I wanted to see how to do it.. which you can see in this pic.  I had my CAV Duran Duran disc playing, obviously.

My thought is that I can do thing similar to the "Rollercoaster" project and just command the thing to play scenes, but it can be taken a step further.

Another option available is to get a user number press from the remote.  The user presses 0..9 and you get that back through the serial port.

It would be possible to make a modern game or interactive video thing using onscreen text for the output, and remote for the input.






The display area on this player is 10 lines of 20 characters each.  Not a lot, but enough for activities.

Perhaps I could encapsulate the game and logic inside of an Arduino would work... but that still brings up the TTL serial issue.










I scoured my basement, looking for my Belkin USB-Serial dongle, which I'm starting to believe I never actually had... I eventually gave up and decided to kludge together this monstrosity.

The nice serial cable I made was a null-modem cable, but the serial level interface (blue board) had the wrong gender and pins for my use, so i tacked on some wires to the correct connector.

The Arduino is a Pro Micro (ATmega 32u4/"Leonardo") made for another project. so it already had the microSD socket and external FTDI connector for a serial peripheral, so this went together substantially quicker than looking for the USB interface.



Regardless, this somehow worked... really well.  I needed to make a simple Arduino program that just reads in from "Serial" port, the USB side of the Leonardo and writes to the "Serial1" port, which is on pins D0 and D1.

The trick was to have both open at 4800 baud.  I had the LD side at 4800 baud, and the USB side at 115200, but that didn't work.

I've made it so I can type on my mac, and control the player... or have the Arduino autonomously control the player.


One of the things you can monkey with is disabling the squelch of the video and audio.  This is what blanks/blues the screen and mutes the audio while seeking, or while doing pause in CLV mode.  When it's off, you can play multispeed/stillframe with audio, stillframe on CLV (which doesn't really work, but it's neat!) and do chapter seeks while still seeing the content.  It's really fun to mess around with...

I think I need to make a script that seeks to the end of the disc to get the duration, then randomly seeks around, plays a second or two, and then repeats that... Especially with squelch off!

Monday, December 5, 2016

RC2014/LL Showing ROM/RAM switching, 64k!

So I thought I'd just make a quick post to show how I know that the ROM swap hardware in my RC2014/LL is working. I'll walk through the procedure here...

First, I booted up the RC2014 as usual, which drops me into BASIC.  From there I wrote this short program:
10 FOR A = 0 to 8192
20 B = PEEK( A ) 
30 POKE A, B40 PRINT A 
50 NEXT A
What this does is goes through the lowest 8 kbytes of memory, reads (peek) and then writes (poke) the byte it finds right back to the place it got it from.   For example:
  1. Read from memory address 0
  2. Write to memory address 0
  3. Switch to the next memory address, repeat 
Which seems stupid, that it does nothing.  But if you remember from a previous post, when the ROM is enabled, it's only enabled for reads.  Writes still happen to the RAM in the same addresses.  So the above program copies the BASIC ROM into RAM.


Next, we switch off the ROM by doing this:
 OUT 0,1
The lowest bit, '1' turns off the ROM, and switches to the RAM for read operations.  To confirm we're working out of the RAM, we can poke a 0 in somewhere down there.

PRINT PEEK( 0 )
 243
POKE 0,0
PRINT PEEK( 0 )
 0
So we can see here that memory address 0 has been changed from 243 to 0.


I also went one step further and yanked the ROM board out of my RC2014.  This is not recommended. ;)  But it did continue to run without any problems... until I really tried to muck things up, for fun:

I wrote a program to clear RAM, and then ran it in BASIC.  Here is the listing:


And here's what happened when i typed 'run'.  It completely locked up after it printed the '8'. Starting at memory address 0x0008 is the text output routine, so it cleared out the boot code before that (0x0000-0x0007), erased the beginning of the print handler, then went to print out something to the screen, and crashed.  Well, I assume it crashed. It got an invalid opcode and who knows what it's actually doing. The code there used to be a "jump" which is 3 bytes.  Instead it got a NOP, which does nothing, (0x00)  and then two garbage bytes which map to something incorrect. Boom!



Sunday, October 2, 2016

RC2014/LL and RC2016/10



The RetroChallenge is upon us again!

This time around, I plan on working on my Z80 homebuilt computer, the RC2014.  (Website for RC2014, Order a RC2014) For a few months now, I've had my RC-2014 computer built, and modified to be an RC2014/LL computer. What this means is, is that I have some modified modules using no additional external hardware.

The above picture shows my RC2014/LL system with its extra RAM module, and the C0 Serial expansion board to the left, with the SD card interface board (SSDD1) on it.

The basics of this design:

Unmodified RC2014 modules:
  • Z80 CPU module
  • Clock module (* see below)
  • Serial console interface
  • RAM module (for RAM in the range $8000 through $FFFF
Modified RC2014 modules:
  • Second RAM module
  • ROM module
  • Digital IO module
Additional hardware:
  • Second ACIA Serial port at $C0
  • SSDD1 (Serial SD Drive)
(*) While the clock module is unmodified, it technically is modified. I have added a 10 uF (50V) cap between the reset line and ground to be a quick-and-dirty power-on reset circuit. It works perfectly.  Every time I power on the computer, it "presses the reset button" for me. ;)

The plans to mod these parts are available here.  This is currently fully functional and tested. The modifications use unused gates on the boards, so that it requires no extra additional hardware or boards to implement. The basic theory to the /LL modifications are as follows:



Bit 0 (0x01) of the Digital IO module is tied to one of the extra bus lines on the backplane.  Let's call this "Extra-A".  When you do an "out" to that port of "0x01", it will trigger the Extra-A line.




The ROM module "out of the box" is configured such that if there is a memory access, which is a read from address $0000 through $7FFF, it will enable the ROM, and it will put its data on the bus.  My modification adds in one extra condition to this.  It adds in that only if the Extra-A line is LOW, that the ROM will be enabled.  This means that when Extra-A is 0, the ROM works. When Extra-A is 1, it's as though the ROM doesn't exist.



The RAM module "out of the box" sits at the high half of memory space ($8000-$FFFF), and is always enabled on memory READ or WRITE to those addresses.  The modification to this module is threefold.  First, it sits the RAM at the low half of memory space ($0000-$7FFF). Secondly, it is set up that WRITEs to this memory space will always work, regardless of Extra-A.  Thirdly, it is set up that READs to this memory space will ONLY work when Extra-A is HIGH.

The end result of this is that when Extra-A is low, reads in the low half of memory will come from the ROM.  When it is high, reads will come from RAM.  Writes ALWAYS go to RAM.

This is quirky...

I admit this.  It means that you can (and I will) write a bootloader/monitor ROM that is enabled on power-on, will read from a mass-storage device and write into anywhere in RAM... It can load a 64 k byte memory image into RAM, and then switch off the ROM and it will all work.  The quirkyness is that you cannot verify the loaded-in memory in the low range of ram, since reads will come out of the ROM.   Obviously, you also need to do this routine completely out of registers, as your stack variables will get overwritten if you're not careful.

Anyway....

If you want it to behave like a stock RC2014, remove the jumper from the IO board to Extra-A, and instead add a jumper from ground to Extra-A.  I have added a switch to mine to force this in the case where the IO board comes up in the wrong state.

Additionally, I have added a second serial port, which basically follows the circuit for the first port, but it sits at $C0, and does not have an interrupt line wired to it.  The RX/TX on that one comes out to a FTDI-like pinout header, which is where my SSDD1 module plugs in.  The plans for this serial port are available here, and can be seen as the brown perf-board on the left of the topmost image of this post.

The SSDD1 module...


The Serial SD Drive module is the mass storage module that I've created for my Z80 to interface with. I know that I can push the FAT filesystem support onto the Z80, but that would require substantial effort.  I instead decided to go with the model where I have a smart serial-based device that you tell it "i want this file" and it sends it out.  Like a local BBS. ;)

The use of a serial-driven drive is not unprecedented.  It's somewhat modeled after the Commodore 64/Vic 20's "IEC" serial interface for floppy drives.  It also mirrors it in that the drive has some smarts in it to deal with the drive architecture.

I also went this route for the ultimate form of this computer, which is to run CP/M.  CP/M expects drives with a Drive+128 byte Sector layout.  While other Z80-CP/M computers implement this by having direct interface to the sectors on the spinny disk/cf/sd card, I will do it by having files on the SD card, for the most amount of flexibility.  There will be a "drives" folder on the card containing folders named "A", "B", "C", and so on.  These letters are the drives.  In each of those will be directories for the tracks, named "0000", "0001", etc and in each of those, files named "0000" "0001" "0002" etc. These files are the simulated sectors on the disks.  It will be easy to build virtual drives for other use out of this.  It also means that I won't need some special interface on a modern computer to talk with this.  I won't have to do 'dd' style transfers to get at the data... It's all just sitting on a FAT filesystem.

The implementation of this module is based on an Arduino with a microSD breakout module.  The serial interface communicates directly with it, and it sends the content via serial back to the Z80 host.

The above picture shows the SSDD1 module off of the RC2014/LL expansion board, and instead wired to a breakout board where I have a second FTDI serial-USB interface so that I can debug the hardware more easily.

And that brings me to the current Retro Challenge...

My goals for this month is to do a few things here, to finish up this computer system...
  • Finish up the firmware for the SSDD1
    • Sector load/save support
    • File load/save of intel hex files
    • directory create, list, remove
  • Write the SSDD1 emulation for the emulator
  • Finish up the loader and burn it to a ROM
  • Write a CP/M bios that uses the SSDD1 interface
  • Build CP/M disk/sector files 
  • Play Zork
Stretch goals:
  • Extend the NASCOM BASIC to support the SSDD1 for loading and saving.


Friday, June 24, 2016

The RC2014 Computer: 1. Emulation


As you may know, I'm bigtime into Z80 computerey stuff.  For the past 20 years or so, I've been hacking Pac-Man ROMs, been maintaining the Ms Pac Disassembly, and have made my own Z80-Pac based programes over the years.

Fairly recently, I got a Kaypro II from a friend at interlock, and it worked perfectly, and looked brand new.  I felt like I couldn't hold on to it... "it belongs in a museum!" ...so I donated it to ICHEG/Strong Museum of Play.  But it helped whet my appetite for a CP/M computer.

Another project I've been wanting to do was to start with a Commodore 64 (I know it's not Z80, it's 6502ish), a floppy drive, some blank disks and a hardware manual and code up, from scratch, an OS.  Start out by making a text editor, assembler, GEOS-like GUI, etc.

These projects recently had an opportunity to overlap, and they all seem to converge on the RC2014 modular Z80 computer.

The RC2014 computer is a backplane-based modular computer created by Spencer Owen, based on the Z80SBC by Grant Searle.  There are modules for the CPU, RAM, ROM, Serial Terminal interface, and so on.  It is available as a kit from tindie.com.  Once assembled, you hook up a serial terminal to it, power it on, and you get a 1980s-esque BASIC prompt onto which you can write your 32kbytes of program.  This is based on Grant's simplified Z80 computer, so there is no off-line storage.

My general plan for the RC2014 is:
  1. Emulation:
    1. Create an emulator for the system to aid with rapid development
      1. also bring my "bleu-romtools" from Google Code to github
    2. Add a serial-based storage solution to the RC2014 emulation to confirm proof-of-concept
    3. Add ROM swap out to the emulation
    4. Add 32k of ram to give a full flat 64k of ram to the emulation
  2. Hardware:
    1. Get a RC2014 kit
    2. Build the RC2014 kit
    3. Make a test ROM to run on real hardware to verify my toolchain is working
    4. Create a new serial card that sits at port 0xC0 (second serial)
    5. Create the SD Drive firmware for the serial arduino
    6. Hack the ROM and Digital IO boards to allow for disabling the ROM
    7. Add 32k hacked RAM to the system
  3. Name: RC2014/LL
    1. At this point, the architecture is different enough and well defined enough that I think a new name for this configuration is in order. I call this configuration "RC2014/LL".
  4. Port CP/M
    1. Create the BIOS
    2. Create the sector-based emulation layer in the SD drive
    3. Boot CP/M
    4. Play Zork


I started out by making an emulator using the Z80 Pack emulation system.  Once I got this running, I realized the limitations of this emulator and looked around and found another emulator that suited my needs better. (I wanted a way to "swap" memory around, which Z80 Pack would not do in a way that wasn't a major hack.)

I created a layer that adds disableable memory regions, and added emulation of the 6850 ACIA serial chip, and threw the 32k RAM BASIC ROM at it, and it started right up, running BASIC!

I added a second 32k of RAM (easy to do when you're emulating it!), and started creating the SD interface, also using the 6850 ACIA for communications.  I then added a port, emulating the IO card, on which bit 0 (0x01), when set, will disable the ROM... So any reads to the low area of memory will read from the ROM.  Whether this is set or not, all writes to that area of memory will actually happen to the RAM... they will just be hidden from reads until that bit is set.

I now have the basics of the RC2014/LL system emulated in software!  I created a boot/diagnostic ROM which can be used for all RC2014 systems which can probe memory to determine type (ROM, RAM, unpopulated), peek and poke memory, In and out IO, and other utility functions for the SD card interface.

Currently, I'm writing the SD card API which I will port to the Arduino Leonardo and SD breakout board which I have ordered, once those come this weekend, I'll shove them into my own serial board and burn a test ROM and see how it goes....

Monday, February 1, 2016

A (mostly) Finished 6502 LlamaCalc(ulator) (RC2016/1 Post-Mortem)


February 1st sees the end of RetroChallenge RC2016/1.  My entry for this month was to create a calculator for the Commodore/MOS KIM-1, by way of 6502 and the KIM-Uno emulation project.  I wanted to have a working somewhat-calculator running on the system, but more importantly, I wanted to learn 6502 assembler.

So let's see what my goals were for this RetroChallenge, as I set them out at the beginning of the project:
Starting today, I'm going to attempt to better learn 6502 asm in my copious amounts of free time for the  RC2016/01 Retrocmputing Competition.  To prepare for this, over the past year I've gotten into working with Oscar Vermeulen's awesome KIM Uno kit, as well as pushing out my own updated firmware for it in the form of my Kim Uno Remix project on github. 
...
For the challenge, I want to use this system to make a simple integer programmer's calculator which I can run on the KIM Uno itself.  Press keys to shift in the nibbles, then switch it into a mode where i can affect the data.  Convert hex to decimal, do bitshifts, add, multiply, etc.
In short, even though I didn't accomplish everything I outlined here, I feel like I was completely successful in the project.  The calculator application is incomplete according to the above feature set, but that wasn't really the goal of this whole thing. I wanted to learn 6502 Asm, which I did. (I didn't finish the BCD to HEX conversions, nor did I implement multiply/divide math functions.)

What were my problems?

I think that one thing that held me back was getting my head around doing multibyte math with only a carry bit. For some reason I got it into my head that this wasn't enough, which of course it is.

Another thing that kept me from getting everything done was that I spent a lot of time to understand the BCD/Hex algorithms.  The code that I used was ultimately very similar to sample code online, but I decided that I really wanted to understand how it worked, so I didn't put it in until that was true.

And of course, just the general lack of time because of various other things including: my daytime job, playing with my kid, two contracts to work on at home, being sick, etc.

What did I achieve?

Over the course of the month, I learned a lot about how to work with such a limited set of registers.  I came from Z80 world where you have a bunch of 16 bit registers.  6502 has one 8 bit accumulator (A), two 8 bit indexing registers (X,Y) which each can only be used for certain operations.

Most everything, seemingly, is done by interacting with memory locations, specifically those in the "zero page". The 6502 has this idea where the 16 byte address's top byte is the "page" of memory.  the memory in the zero page would be bytes from $0000 through $00FF.  This is generally used for OS and general use variables, etc since there are small opcodes specifically for working with them.

I'm getting into too much detail. I'll instead outline all of my accomplishments for the month...

  • Learned 6502 ASM
  • Improved the "KIM Uno Remix" Desktop application (QT for portability)
    • Added a memory snooper
    • Better graphics palette
    • More speed support
  • Learned indexing (using X and Y registers)
  • Wrote the LlamaCalc input routine 3 times, learning 6502 opcodes better each time
  • Came up with a decent user interface for LlamaCalc that's somewhat learned-intuitive
  • LlamaCalc features implemented:
    • Display/UI states for LlamaCalc (Splash, Result, Menu, Error)
    • centralized interface for doing math functions, error handling, etc
    • 8 level stack of numbers to be used (changeable at build time)
    • Push/Pop stack functions
    • Hexadecimal to BCD conversion
    • bit shift left by one bit
    • bit shift right by one bit
    • 24 bit addition
    • 24 bit subtraction
  • Designed an RLE compression scheme for graphics
  • Added RLE decompressor to the source code projects
  • Played with optimizing screen display
  • Oh yeah, created a full repository for 6502 code, with libraries etc. on github
  • Every time I learned something new, I created another project in the Projects6502 repo

So yeah. I feel like i was successful...


I will soon have a walkthrough of using LlamaCalc using a KIM-Uno device.

Here's the source code for everything:

Monday, January 25, 2016

6502 - 24 Bit Math and a little BCD (RC2016/1)

I decided that another experiment/lesson to do on my way to making my calculator app was to learn how to do multibyte math and possibly experiment with BCD/Decimal vs Hexadecimal. (Or as Mark Watney calls them "Hexidecimals".

I kinda like breaking down this project into multiple "lessons" as it were.  It makes me feel like I'm following along lesson plans in a book.  Perhaps I should go the other way around and actually make the book I would be following if I were following a book to make this thing.

The code for this can be found in my github repository.

I broke down the application into a few main steps:

  1. display the last result
  2. add together the two previous results
  3. store that sum into a result variable
  4. repeat
When broken down further, we see that we also have to have some method for "kickstarting" it, as it were, since the first two numbers in the sequence do not follow the standard fibonacci sequence. (quick reminder: each value in the fibonacci sequence is the previous two values added together. very simple.  So, for the first two values, there is no "previous two" so they are just hardcoded as "0, 1"

Computation of the sequence can be described as :
  1. hardcoded "0"
  2. hardcoded "1"
  3. use algorithm to sum previous two values
  4. same as 3
  5. etc
For doing the math, I wanted to have variables that mimiced the 3 bytes we are able to display on the KIM, so I use 24 bits (3 bytes) to store them.  I broke down the math functions to be generic in that they can perform using two variables ("i" and "j") and store their result in a third variable "RESULT".  From there, additional functions were created to move the values around between them.  For example, we need to "roll" the values through if we want to make this repeatable. So the computation sequence can be described as:
  1. RESULT, I and J all set to '0'
  2. refresh display RESULT "0"
  3. RESULT gets "1"
  4. refresh display RESULT "1"
  5. shift the values through:
    1. J gets I's value
    2. I gets RESULT's value
  6. add:  RESULT gets the value from adding I and J
  7. repeat at step "4"
And this is basically the procedure as seen in the source.  

The multibyte addition was actually a lot simpler than I thought it was going to be. My first thought was "how could this possibly work if i were to add like 100 to 100... you end up with "2" for the carry instead of "1"."  Obviously, you can see the error here, but for some reason this got stuck in my head and suddenly, all of the multibyte (16+ bit) math seemed near impossible to deal with.  I think it was the multiplication that seemed hard, but when you break it down as multistep additions instead of multiplications, it all makes sense.  I blame this on the cold and fuzzy head I have right now.  I'm just not thinking right... also extra time at work... sure... and um... an ARP storm.  all contributing factors to not thinking clearly. ;)

The basic procedure for doing multibyte math is to observe the carry bit.  The carry bit is set when math on two 8 bit values exceeds the 8 bit container.  If you think of it in decimal, when you add 1 to 9, you get "0" with a carry of "1" which ends up in the next digit space, resulting in a "10".  So if you were to add 99 and 04, you end up with 03 with a carry of 1, resulting in "103".  Math on the 6502 is no different, other than we're (probably) using hex where the value can go from 0-9,a-f rather than just 0-9 for each digit.  The math for addition is basically:
  1. for each byte (starting from the least significant on the right)
    1. add one byte to the other, with the carry bit from the previous byte
    2. store that result in the RESULT
Or, more precisely
  1. clear "Carry" (Carry = 0)
  2. register A gets I0 (A = J0)
  3. add j0 to A.  (A = A + J0 + Carry)
  4. store the result in RESULT0
  5. A = I1
  6. A = A + J1 + Carry
  7. RESULT1 = A
  8. A = I2
  9. A = A + J2 + Carry
  10. RESULT2 = A 
I think you can see that this can be carried out indefinitely for multiple bytes.

The "display the result" was pretty straightforward as well.  The "RESULT" bytes were stored into INH, POINTL and POINTH, and then the SCANDS function is called. This refreshes those three values out to the KIM's LED display.  Then a call to GETKEY stores the current key press value into the accumulator register.  If nothing is pressed, this fills A with $15, or KEY_NONE as I have it defined.  Then it just sits in a tight loop refreshing the display and waiting for any key to be pressed.
  1. refresh display
  2. check for key press
  3. no key press? repeat at 1
  4. return
So the end result is a program that advances to the next sequence number each time you press a key.

When it fills all the digits, when we get a "carry" on the third digit while doing the math, i display "EEEEEE" as a cheesy error display and wait for a press.  When something is pressed then, it resets and starts all over agian.


As for BCD, I basically have run the code both in BCD (decimal) mode and hex mode, just to see how it works out.  Turns out i was worried for nothing,  It all 'just worked' fine in both modes.

So yeah.  My throat is sore, and I'd love to just go to sleep right now.

Thursday, January 21, 2016

6502 - RLE Image Renderer (RC2016/1)


I finished up my RLE (Run-Length Encoded) image renderer last night.  It would have been much simpler but there were a few things that I wanted to deal with to have proper full support for sprite placement and large image rendering.

The basic concept of RLE is that instead of storing just a series of pixel colors, we also store the number of times each pixel is repeated.  As described in the previous post, we know that this hardware uses the lower nibble of each byte to store the color number.  We will use the upper nibble to indicate repetitions as well as other commands, which we'll get to later...

Using '0' for the number of repetitions makes no sense, so it will never be used when the image is encoded. (repeat "red" pixels 0 times? nope.) So we'll use '0' in the top nibble to indicate commands.  A few commands that we will need are:

$00 - End of image (stop rendering, return)
$0F - End of line (no more pixels on this line, start over vertically down one pixel from the start of this line)

Which leaves $01 through $0E, which we will use as a "skip".  Advance the screen position, but do not draw any pixels to the screen. We can use this to allow images to have "transparency".

One thing to deal with was that after 255 bytes (at most), the referencing will go into another bank.  If everything fits in one bank, that's fine, but the screen itself is 4 banks, so this was something that needed to be addressed.  (HA! Addressed! I'm hilarious!)  If this isn't dealt with, and we only are incrementing the lower byte of a two byte address, we'll just keep reading (or writing) forever inside of one bank. $41FE, $41FF, $4100, etc  rather than $41FE, $41FF, $4200, $4201 ...

So basically instead of just incrementing the screen pointer by one, indirectly using
    inc IMGPTR    ; will wrap around inside a bank. bad.
I instead had to add a '1' to it, then add the carry bit onto the high byte of the value.  I need to take a step back here.  The 6502 only really has grasp of 8 bit (one byte) values.  It can use 16 bit values for addresses, stored as two bytes, but all math functions happen on the one-byte scale.
    clc          ; clear the carry bit  (Carry = 0)
    lda IMGPTR   ; A = *IMGPTR
    adc #$01     ; A = A + 1 + C
    sta IMGPTR   ; *IMGPTR = A
      ; at this point, the carry bit is either set or not,
      ; so we will add 0 into the next byte with carry
    lda IMGPTR+1 ; A = *IMGPTR+1
    adc $#00     ; A = A + 0 + C
    sta IMGPTR+1 ; *IMGPTR+1 = A

Why use RLE? A couple reasons.  First of all, it will save ROM space.  The RLE encoded (compressed) images should take a bit less space inside the rom.  An alternate we could do is to store color data in both nibbles of the byte, then just shift them out to the screen.  We would lose the ability for transparency, but you're guaranteed 50% space savings with the system we have here.

The full source code for this project is over at github.

The image shown at the top of this post shows three sprites stored in the ROM.  They were hand-encoded from graph paper sketches of various sources.  The rainbow was just coded by scratch to test out everything.

The red ghost is obviously borrowed from Namco's "Pac-Man" arcade game.  The mouse is borrowed from Nintendo's "Goonies" arcade game. Both are used for educational/demonstrative purposes here.

Wednesday, January 20, 2016

6502 Learning (RC2016/1)... Video buffer sidetrack...

I got a little sidetracked while working on the KIM-Uno calculator, playing with video buffers. I had added a video buffer to the desktop Kim Uno Remix project. Ultimately, I want to make a compressed image decoder and viewer.. to draw sprites to the screen or full-screen images.

I've written stuff like this before back on the Z80 for Pac-Man hardware, so I thought it would be a fun exercise to see how something like this would be implemented on 6502. It gives me a good chance to learn addressing modes and methods for this architecture... which is very different than Z80's.

You can attempt to play along by using this web-based assembler system. I based the video buffer in KIM Uno Remix on this system.  There are a few differences though...

6502asm.com:

  • 32x32 pixels
  • 16 colors
  • Commodore 64 palette
  • starts at $0200, continues horizontally then down, starting top left
  • one byte per pixel
  • bottom nibble indicates the color ($00..$0F)
  • top nibble is ignored
  • code starts at $0600
KIM Uno Remix:

  • is 32x32 pixels
  • 16 colors
  • Modified Deluxe Paint palette
  • starts at $4000, continues horizontally then down, starting top left
  • one byte per pixel
  • bottom nibble indicates the color ($00..$0F)
  • top nibble is ignored
  • code starts at $0200
Here's the output from a small program (shown below) that shows off the palettes of the systems. The KIM Uno is on the left, and shows the very reasonable "rainbow" palette.  The one on the right shows the more convoluted "Commodore 64 palette" of the web tool.


The colored sections are 8 rows of 32 pixels across. Since there's only 16 colors, the color stripes get repeated twice along the horizontal of the screen.

The code to run the above was essentially identical on both systems but there are some tweaks to accommodate the addresses and some minor differences between the CC65 tools that I use and the web-based tool.


Here's the source code listing used for CC65, which generated the image on the left above.  You can see that it writes to two of the four banks of memory space, at $4000 and $4200, while not doing anything with the $4100 and $4300 banks, which is why we see two segments of stripes, and two segments of black in the above image. It is a very simple program that simply increments "X" and writes it to videobuffer[x].


And here's the source for the web-based tool.  I colorized it to match the above CC65/KIM Uno Remix listing.  Notice that the program is the same, although it uses $0200 and $0400 for the screen memory, skipping the $0300 and $0500 sections.  I also switched the "unnamed label" from the above code to be a label named "loop" for this one.  It apparently doesn't support that.