Sunday, September 15, 2024

No name IPS 240*240 ST7789 TFT display with Arduino GFX Library and ESP32-C3 (RISC-V) development board

 

This is an alternative take on the previous article Adafruit ST7789 TFT display with Arduino GFX Library and M5StampS3.   This time with a generic display, and a different MCU (ESP32-C3).  This one has a single RISC-V core (instead of dual core Xtensa).

So excuse the repeated text, the content has been changed only slightly for the different hardware...


Attaching a display to a circuit can provide a lot of detailed info and graphical value.  While "a picture is worth a thousand words," an animated display can be entertainment value, textual information can be informative, and add an input device, and the system can be interactive with billions of possibilities.

The tricks in embedded development is choosing the right display, having the right library that supports the display, and figuring out to use it all together with your target embedded system.

Shown above is a minimal footprint ESP32-C3 development board (I purchased one from AliExpress for around two US dollars, very cheap!), with a generic IPS 240x240 TFT display (ST7789 based) I had purchased years ago on eBay.  An SPI interface is utilized for communications using the GFX Library for Arduino.  I am using a solderless breadboard to prototype the circuit.  Later I will implement as a more permanent circuit.

Besides power and ground, there are only 4 connections from the ESP32: SCLK, MOSI, DC, and Reset.  In this sample, the TFT select line is permanently selected by connecting to ground.

#include <Arduino.h>
#include <Arduino_GFX_Library.h>

Arduino_DataBus *bus = new Arduino_HWSPI(6/*dc*/, 7/*cs*/,
   2/*sclk*/, 3/*mosi*/, 10/*miso*/, &SPI,
   true/*is_shared_interface*/);
Arduino_GFX *gfx = new Arduino_ST7789(bus, 11/*rst*/, 1/*r*/,
   true/*ips*/, 240, 240);

void setup() {
  gfx->begin();
  gfx->fillScreen(BLACK);
  gfx->setTextColor(WHITE);
}

void loop() {
  int x = (int)random(240);
  int w = (int)random(240 - x);
  int y = (int)random(240);
  int h = (int)random(240 - y);  
  int color = (int)random(65536);
  gfx->fillRect(x, y, w, h, color);
  if (random(20)==13)
    delay(100);
}

The wiring corresponds to the code of the databus and gfx initialization parameters, specifically lines GPIO02 (SPI CLK), GPIO03 (SPI MOSI), GPOI06, GPIO11 of the ESP32-C3 connected to SCL, SDA, DC, and RES (Reset) of the display respectively.  Also both the VCC and BLK lines of the display are connected to 3V3, and GND is connected commonly between the display and ESP32-C3 board.  MISO and CS lines are defined for use in the code, but wiring them was unnecessary and not possible.

TFT   ESP32-C3
GND   Ground
VCC   3V3
SCL   SPI Clock (2)
SDA   SPI MOSI (3)
RES   (11)
DC    (6)
BLK   3V3

Not sure why triangles are sometimes displayed (maybe out of range data?).  That is why there is a 5% chance of a tenth of a second delay to pause for the viewer.

This is just a demo.  You should be able to find much better uses for the display that these random rectangles.

Build details:
  • Arduino IDE 2.3.2
  • esp32 boards 3.0.4
  • GFX Library for Arduino 1.4.7
Important!  The board I have will only run its flash chip in DIO mode, so be sure to check all the board options in Tools menu of Arduino IDE before flashing, or if you run into trouble.  Also, updating board libraries may reset your options to default so if flashing after a time, check these settings again, and again.

Some models of the ESP32-C3 development board have a serial chip, and some utilize the C3's built in USB support.  Be sure to set USB CDC on Boot settings accordingly, and use the BOOT/RST buttons to put into bootloader mode for flashing if necessary.

I found it necessary to unplug and replug the ESP32-C3 board to get the graphic demo to work.  Your mileage may vary.

Sunday, September 8, 2024

Adafruit ST7789 TFT display with Arduino GFX Library and M5StampS3

 


Attaching a display to a circuit can provide a lot of detailed info and graphical value.  While "a picture is worth a thousand words," an animated display can be entertainment value, textual information can be informative, and add an input device, and the system can be interactive with billions of possibilities.

The tricks in embedded development is choosing the right display, having the right library that supports the display, and figuring out to use it all together with your target embedded system.

Shown above is a minimal footprint ESP32S3 in the form of an M5StampS3 from M5Stack connected to 2.54mm pins, with a rounded corner ST7789 based 280x240 display from Adafruit.  An SPI interface is utilized for communications using the GFX Library for Arduino.  I am using a solderless breadboard to prototype the circuit.  Later I will implement as a more permanent circuit.

Besides power and ground, there are only 4 connections from the ESP32: SCLK, MOSI, DC, and Reset.  In this sample, the TFT select line is permanently selected by connecting to ground.

(The Adafruit display used in this example also includes a MicroSD connector and SPI connections for that as well.  Support for SD is beyond the scope of this article, and would require additional changes to the circuit and code.)

#include <Arduino.h>
#include <Arduino_GFX_Library.h>
Arduino_DataBus *bus = new Arduino_HWSPI(1/*dc*/,
  GFX_NOT_DEFINED/*cs*/, 7/*sclk*/, 5/*mosi*/,
  GFX_NOT_DEFINED/*miso*/, &SPI, true/*is_shared_interface*/);
Arduino_GFX *gfx = new Arduino_ST7789(bus, 3/*rst*/, 1/*r*/,
  true/*ips*/, 240, 320);

void setup() {
  gfx->begin();
  gfx->fillScreen(BLACK);
  gfx->setTextColor(WHITE);
}

void loop() {
  int x = 20 + (int)random(280);
  int w = (int)random(300 - x);
  int y = (int)random(240);
  int h = (int)random(240 - y);  
  int color = (int)random(65536);
  gfx->fillRect(x, y, w, h, color);
  if (random(20)==13)
    delay(100);
}

The wiring corresponds to the code of the databus and gfx initialization parameters, specifically lines 1, 3, 5, 7 of the M5StampS3 connected to DC, RT (reset), SI (serial in), and CK (clock) of the display.  Also the displays V+ line is connected to 5V, and both TC and G (Ground) are connected to ground common to the ESP32 S3.

TFT   StampS3
V+    5V
3V    NC
G     Ground
CK    SPI Clock (7)
SO    NC
SI    SPI MOSI (5)
TC    Ground
RT    (3)
DC    (1)
CC    No Connection
BL    No Connection

It appears there is an overscan issue, beyond the rounded corners.  The gfx object is defining 320x240 display instead of 280x240, and the position and sizes of the rectangles are also interesting here.

Not sure why triangles are sometimes displayed (maybe out of range data?).  That is why there is a 5% chance of a tenth of a second delay to pause for the viewer.

This is just a demo.  You should be able to find much better uses for the display that these random rectangles.

Build details:
  • Arduino IDE 2.3.2
  • esp32 boards 3.0.4
  • GFX Library for Arduino 1.4.7

Sunday, August 25, 2024

Wireless controller adapter for Commodore

 


It's August 2024.  I've just bought a new (to me) Vic-20 for US$50 to replace my childhood one.  I already have the PenUltimate Vic-20 Cartridge with a ton of games.  I also bought a Hyperkin Trooper joystick.  But I want to game wirelessly!

I've already had great success with a BlueRetro Nintendo GameCube controllers wireless adapter with my original Wii game console.  I purchased it on ebay for a good price and it worked great.

But I wanted to go back further to replacing an Atari joystick on my Commodore Vic-20 that has a DB-9 connector.  Searching the Internet, it looks like BlueRetro internally supports Atari 7800 with a 2-player mode, and there is a single player version available for sale on Amazon for about $25.  Also the ESP 32 firmware source code is available as open source.

Having experience developing with ESP32, and a plethora of electronic parts already at my disposal, I did what any enterprising consumer would do -- I purchased additional parts from AliExpress.  I mean, you can't have enough electronic parts, can you?  Okay, I could've done it completely from scratch but my time is valuable, I have only so much energy at the end of the day, and cheating my way to success is legal here.   So we're doing it halfway.

First I bought the BlueRetro Core.  It provides the base functionality with a DB-25 connector for all its pins.  It is designed to allow connector adapters to be wired to various console systems.  It is a very creative and functional design.  And there are adapters available for many of the common systems.  But I didn't have any luck finding Atari connectors.

But no problem!  I can build my own!  So I found a DIY screw terminal DB25 male connector with the correct optional mating screws, and the counterpart DB9 female connector with screw terminals.  The only trick left is to wire it up.

Steps

  1. Connect BlueRetro Core to USB power adapter (don't require direct connection to computer)
  2. Download latest firmware ZIP via link provided on BlueRetro support site
  3. Unzip, and look for the parallel 2P firmware (1P should work fine too, skip the 3V3 versions.
  4. Follow flashing firmware instructions from BlueRetro support site
  5. Pair a supported wireless controller (I'm using an Xbox One Bluetooth compatible controller)
  6. Plug BlueRetro Core into the DB25 breakout
  7. Connect a voltage meter to ground on the breakout, and then test the voltage at each remaining pin with and without pressing a button (e.g. DPAD up/down/left/right, and A)
  8. Write down the DB25 pin numbers and the names of the controller functions
  9. Unplug the core, and power off for now
  10. Search the internet for the DB9 pin numbers for Atari joystick connector pinout so you have their functions handy
  11. Cut and strip ends of 8 wires of different colors long enough to connect the DB9 and DB25 breakouts
  12. Be sure to first feed the wires through the included rings, and confirm their orientation.
  13. Then connect the appropriate functions: up, down, left, right, fire, framing ground, signal ground, and voltage in  (VIN) to +5V supply from Commodore/Atari
  14. Minimally connect, and test the functionality first with meter, then with Commodore/Atari console
  15. Once verified working, finish connecting wiring stress-relief, bolt the enclosures closed, and otherwise button-up and tidy up the solution.
  16. Play games!
DB25-1   to DB9-4   (right)
DB25-4   to DB9-3   (left)
DB25-GND to DB9-GND (frame ground)
DB25-7   to DB9-7   (VIN to +5V)
DB25-8   to DB9-8   (signal ground)
DB25-13  to DB9-6   (fire)
DB25-15  to DB9-1   (up)
DB25-17  to DB9-2   (down)

Another link to support this wiring is the BlueRetro Hardware Design documented over at hackaday.  There are schematics showing signal ground and VIN with the DB25 pinout.

I had fun with this effort, and should be able to expand this effort to support a second controller simultaneously connected to the same core, or wire up adapters for other systems myself.

The cost of the solution for me was about $22 with shipping, and as I was careful to choose items shipped directly from AliExpress and live on the west coast of USA, received the items quickly in about a week.  While this didn't save me the labor and only saved $3 from the Amazon solution, I learned a lot and feel comfortable leveraging the result to make solutions for other consoles and a second player.

(Any of you worried about 5V tolerance on the ESP32 or the buffer chip included with BlueRetro Core?  The Commodore is at 5V, and while the ESP32 is powered by 5V its IO is exclusively 3.3V.  It works for me without any additional consideration, but your mileage or concerns may vary.  You can usually get away with it for ESP32 as many of the IO are designed to survive 5V, and a 3.3V high signal does read as a high signal with most 5V systems.  So am I just getting away with it?  Maybe.)

But wait! Some keyboard lines are not working. I'm not done yet!

So with some prototyping, it turned out that the circuit to the Vic-20 needed to be open drain instead of push-pull. Pulling down was fine, but something was amiss with pushing 3.3V (or even 5V with other attempts) from the ESP32 BlueRetro Core circuit.

How does an Atari style joystick work anyways? There are 4 directions and one extra button. When any of them are active, the associated line is connected by a switch to ground. The BlueRetro Core simulates this by pulling to ground just fine, but when idle, it is pushing 3.3V. And the Vic-20 has its own 5V pull ups. That does sound messy. Somehow (without looking at the various schematics) this appears to cause a conflict so the 2, 4, etc. and F7 keys for example don't work anymore, they can't pull down to ground when this joystick circuit is attached.

So let's think how to correct this.  We want the connection to ground when the joystick is active, but we want high impedance (appear disconnected) when the no direction or selection is made.

The solution is a circuit that can perform this.  At first I'm thinking I don't have any FETs left over from previous projects, but finally after using one of my go-to buffer chips in breadboard circuits trying to solve this thing, I finally remembered that instead of being annoyed there are enable inputs for each buffer, the enable inputs can function as the inputs from the BlueRetro Core.   They are enable low, so when the joystick selection is made, the circuit will connect, and can take a grounded low input and buffer that to the Vic-20 joystick port.   So when the button or movement is made, the circuit will be grounded low, but otherwise that individual circuit is disabled (high impedance) as if the switch is not connected.  And this separates the 5V Vic-20 circuit from the 3.3V BlueRetro Core (ESP32) circuit.  And best of all, testing on breadboard, it works great!   The keyboard is now functioning normally with the joystick circuit powered and connected, and is still self powered from the Vic-20.

The revision to the above wiring is to connect DB25 joystick lines to OE/ lines of a SN74AHC125N, connect ground to the A lines, and connect the Y lines to the appropriate DB9 joystick lines. Also connect 5V power (14) and ground (7) to the appropriate IC pins.  And since there are five joystick lines, and this is only a quad (4) buffer part, we're gonna need two of them (and three if extending to two joysticks for dual player such as with a C64 or Atari 2600 VCS).  I recommend setting the unused enable lines for the extra buffers high (5V) to disable their outputs.

Again, these buffers are only for up/down/left/right/fire(select).   The voltage and ground wires should be wired between the DB25 and DB9 without buffering.


Sunday, August 11, 2024

Vic-20 memory configurations supported by emulator


The C128 team invented the GO64 command for compatibility.  Years ago I claimed to invent the GO128 command, and GO20 and some others.

My Commodore emulator (unified branch) that supports Windows and LCD targets including compact watch form factor, now supports an argument to the GO statement to specify the total memory to configure.

The Vic-20's memory map looks roughly like this.

//   (from emuvic20.cpp)
//   $0000-$03FF Low 1K RAM
//   $0400-$0FFF (3K RAM expansion)
//   $1000-$1DFF 3.5K RAM (for BASIC) [or alternate screen address]
//   $1E00-$1FFF 0.5K RAM (Screen characters)
//   $2000-$7FFF (24K RAM expansion)
//   $8000-$8FFF (Character ROM)
//   $9000-$9FFF (I/O)
//   $A000-$BFFF (8K Cartridge ROM, or RAM expansion)
//   $C000-$DFFF BASIC ROM
//   $E000-$FFFF KERNAL ROM

The Vic-20 was manufactured with 5K RAM, with only 3.5K available for BASIC, not counting the color RAM nybbles (half-bytes).

There is a missing hole of 3K RAM in lower memory, cartridge sold separately.   And you could also purchase 8K or 16K RAM cartridges.  And later on 24K and 32K solutions.   Up to a total of 35K RAM can be added into the memory map.

So specify the amount of RAM you want to add, and rounding down, the emulator will populate the appropriate memory.

But only 27.5K is available to BASIC programs.  1.5K is reserved for system use, the lower 3K RAM is only available to BASIC in some instances, and an upper 8K is reserved for cartridges and otherwise not contiguous, so also not available directly for BASIC use.

The VIC video chip (named VIC) can only address screen memory on the main board, so when both 3K and 8K memory expansions are populated, screen memory is directly in the middle, causing Commodore BASIC to ignore the lower 3K memory to prioritize for the larger contiguous memory configured after screen memory.  The 3K lower memory is only used directly when it is the only contiguous RAM expansion, such as with the separate 3K memory expansion cartridge and with the Super Expander that included 3K RAM expansion, but stole more memory for the programmable function keys, and for the graphics screen.

GO 20        (default, 3583 bytes free)
GO 20, 5    (minimum, 3583 bytes free)
GO 20, 8    (5K, +3K, 6655 bytes free)
GO 20, 13
    (5K, +8K, 11775 bytes free)
GO 20, 16    (5K, +3K, +8K, 11775 bytes free)
GO 20, 21    (5K, +8K, +8K, 19967 bytes free)
GO 20, 24    (5K, +3K, +8K, +8K, 19967 bytes free)
GO 20, 29    (5K, +8K, +8K, +8K, 28159 bytes free)
GO 20, 32    (5K, +3K, +8K, +8K, +8K, 28159 bytes free)
GO 20, 37    (5K, +8K, +8K, +8K, +8K, 28159 bytes free)
GO 20, 40    (5K, +3K, +8K, +8K, +8K, +8K, 28159 bytes free)

Note that many of these show the same number of bytes free even though extra memory has been added. This again is because only contiguous RAM can be configured as available to BASIC.  The extra RAM is available for PEEKs, POKEs, and other machine language programs.

If a number out of range is entered, it is effectively rounded down to a valid configuration.  For example GO 20, 64 will configure with 40K RAM.   But 5 is the minimum, so GO 20,0 will configure 5K RAM.

Technically the Vic-20 tests for and can handle memory added in smaller configurations, but that's not commonly present in reality, and not how I implemented it.   Also I only implemented adding 8K memory forward in the map (with the exception of the 3K coming and going based on math), and not configuring each section separately.  Going with a total RAM value is a simpler concept to implement and understand.

Please enjoy the Vic-20 with extra RAM!


Save capability added to C64 version of VWAS6502 monitor


Save has been added to my 6502 monitor program for the C64 version.  The video above demonstrates creating a very simple 6502 program to output printable characters to the screen, and saving that program to disk.

Loading is not implemented, but you can easily use BASIC for that task as demonstrated.  Not explicitly shown is the X command to exit to BASIC.

The new save syntax is in the following form:

1000.2000 "FILENAME" 08 S

Tuesday, July 30, 2024

Snapshot feature implemented for MINIMUM 6502 mode

 


This snapshot feature is for the minimum 6502 emulation target included in c-simple-emu6502-cbm (unified branch).  (This is a bare bones 6502 target with CPU/RAM/ROM/UART.  The UART is MC6850.  See SWEET-16 and vwas6502 previous discussions.)

Ooo.  The screen is so fancy.  F2 or F3 to bring up this screen.  Up/Down make a selection.  Return performs load or save for that slot, or return on the slot number allows up/down to change the slot number.  When loading, the current state is replaced by the state loaded from disk.  When saving, the current state is backed up to disk.  (The reason for the Up/Down/Enter UI choices is that it can be performed by three buttons or touch equivalents with the supported M5Stack devices.)

F2 defaults to SAVE

F3 defaults to LOAD

This is about the simplest way to provide a general load/save functionality without implementing a higher level monitor.  The state includes 6502 CPU, RAM, ROM, minimum settings (where MC6850 is mapped in memory), terminal state, and UART state.  The data is serialized to a binary blob and stored as a single file with the name state01 or such.   Pretty imaginative huh?

So, now you can use the machine language monitor, or Apple 1 BASIC, or whatever you have ported or implemented to this system, and save a current snapshot of the system to restore later.

Example:

6502 hello world

In the example screenshot, I have restored a snapshot from a previous session where I created a program to display the visible ASCII characters 32 through 127.

So in the future, I can expand on the program, save the current state, and resume where I left off another time.  Also the snapshots can be transferred between systems running the emulator.  In my case, I can run on Windows, or M5Stack CoreS3, or Sunton 7".   Switching is a breeze of copying files to/from microSD. 

I hope this feature is useful to others as well!

Tuesday, July 16, 2024

6502 Help References included in 6502 monitor

6502 mini-assembler help system

The help system recently added to the 6502 monitor (vwas6502) includes
  • help commands
  • monitor commands reference
  • 6502 instruction set mnemonics
  • 6502 addressing modes references, listing valid instructions
  • opcodes with addressing modes available for a specific instruction mnemonic
In observation, that required a bit of ROM memory.  The monitor is currently at 4K with minimal features.  It is bursting at the seems without further space optimization, so will need to expand to 8K with the next feature additions.

Help commands





Monitor commands reference


6502 instruction set







6502 addressing modes

















Help for a specific instruction









The references are possible, because the mini-assembler and disassembler is table driven.  There is a table of instructions in alphabetical order, an alphabetical index of the addressing modes, a table of addressing modes and an example for each in parsing (and number of bytes required) order, and tables of the opcodes: (ordered by) byte values, index to instruction name, and index to addressing mode.

By using the alphabetical indexes, the information can be displayed sorted when applicable.  This makes the information more easily accessible.

The 6502 specific references are generated by 6502 code on demand from the tables.  The commands reference and help about help are the only static help pages.  It would probably take a lot more storage if all the references were static, especially considering there are 56 separate instructions.

More information about this monitor is available in the previous article.

Friday, July 12, 2024

Mini-assembler with disassembler, display, edit, and run

 

Sample assembly entry and run example

Links
  • Source at github
  • D64 and PRG from github (Commodore 64)
  • BIN for ROM (minimum system 6502 + MC6850 + RAM + ROM)

Everyone (in a small corner of the retro programming community) has their favorite machine language monitor.  Mine is HESMON for the Vic-20 which I got in the early 80s.  I probably also used TinyMon, and have used SuperMon in recent years.  The VICE monitor (ALT+H) is great, especially like the symbolic label support which I use to debug my programs assembled with ACME.  Also the Commodore monitors are great too, including Commodore 128 and Plus/4 (and family).

But recently I've been playing with WozMon, both in a a minimal emulated 6502 system, and compiled for Commodore.  But I didn't have a great disassembler and assembler to go with it.   I looked around a little (probably not enough).

My programming brain and fingers were itching to build my own.  So I set out to prototype the assembler portion in C#, the disassembler in 6502 using tables generated by the C# experience, and finally created a wozmon compatible monitor in 6502 with both disassembler and mini-assembler as we see here today.

Let's cover the syntax briefly.

Display memory is a single address (up to 4 hex characters) either by itself, or two addresses separated by a dot for a range of memory.  Below we are looking at the C64 jiffy clock by entering "A0.A2".   The result is the starting address followed by a colon and three bytes of memory from that range.











Modify memory is similar to the output of display memory, but you enter it.  (No I didn't implement the Woz's feature of showing the previous value of the first address.  Probably nice to add later.)   Either a single byte, or multiple bytes may be entered and stored into memory at the specified address.









Run program is a hex address followed by R.   Note that an RTS will usually return to BASIC.  And a BRK will perform the normal screen reset routine.   So best bet for now is to JMP $C000 to return to the monitor (if you wish).   Or if you want to reset the C64...









Those are the commands I stole from WozMon.   (To be clear, I didn't steal the code, just the syntax.  This is my code.)  To continue the excitement of working with WozMon.  With the interest of creating something bigger and better.  Oh joy, more generic machine language monitor commands.   Yes!  You guessed it!

Disassemble is similar to the run command, just change to a D


















Assemble is where the exciting things start to happen.  Use A after an address to start writing your own programs in 6502 assembler.






















And look what an exciting program this is!   Nearly(*) at the speed of light, it is outputting the first three numerals before restarting the monitor.   Wow!   I am speechless.   (*)I may be too excited about this.

There you have it!   An assembler, disassembler, memory display, editing, and running.   What else could you ask for?

Program loading and storing?

Oh excuse me, I must be going now.   Can't quite hear you.   Enjoying the spendor and excitement of new features.   Ah, while I bask in the glory of greatness.  Let me enjoy this, will you?

Later  dudes!

Update 2024-07-14 The project now also builds a ROM image for a bare-bones 6502 system with MC6850 UART.  The source code has conditional compilation for portions whether the system is first a Commodore 64 with full screen editing, secondly only using the get key routine terminal style (used as stepping stone to...), and lastly the minimum 6502+6850MC.  Also is an option whether to echo keystrokes back to the terminal.   The monitor with mini-assembler and disassembler is now available to more easily port to other 6502 systems!

6502+MC6850 emulated system debugging its own input line routine

Tuesday, July 9, 2024

Disassembler for use with WozMon

 

Disassembler disassembling WozMon

WozMon is a great little monitor program in 256 bytes which Steve Wozniak wrote for his Apple 1 release in 1976.  It was small but powerful allowing for memory inspection, entry of 6502 machine code programs and bytes, and launching of programs in ROM and RAM (jumping to address).

But being small, it is missing features that monitor users have learned to depend on, including a mini-assembler and disassembler.

So here I am today presenting a disassembler I wrote for 6502 which can be integrated with WozMon run command.  Once the disassembler gets control, the Y register contains a pointer to the last character read from the input buffer, and continues parsing for a hex address.  If not found, it simply returns to WozMon.  But if found, it will disassemble 20 statements starting at that address.  (Note: Vic-20 port above, changed to 17 statements due to the smaller screen size).

The syntax may be lengthier than other monitors, but it allows for an integration with the normally ROM based WozMon without modifications.  Plus you get what you pay for.   The disassembler is open source, so feel free to change it.

The disassembler came into being as part of developing a mini-assembler.  First I'd written a prototype in C# .NET. 

The assembler included tables of information for the 6502 instruction set and addressing modes that lent itself to be used as a disassembler (came second) which was prototyped as a 6502 program that disassembles itself.  Third came the disassembler compatible for use with WozMon.

Each prototype and program is one step along the way for the goal of creating a mini-assembler for my 6502 minimal system.  Not there yet, but getting closer with each step!

Also works with original WozMon in Apple 1 style environment

Also works on C64 and C128 systems


Wednesday, June 12, 2024

Strings or Compact directory utility for C64


Directory listings scrolling by too fast?  Want to scan program for string literals?  Here's a stupid (sometimes useful, definitely ugly) utility I created in the monitor for both scenarios.  Compact display and pauses every 24 lines.  Attempts to avoid control characters.

Note: operates on whatever loaded program is in memory, assuming BASIC. 

Shown loading into tape buffer (828), can be relocated. 

This source is an example of parsing a BASIC program.  The beginning of BASIC is grabbed from $2B/2C, and each line of the program is iterated through traveling its linked list ending with a null pointer.  In each line, a string starts with double quotes and ends with double quotes or end of line (zero or nul character).  Multiple strings per lines are possible.   Other memory addresses used include toggling the reverse flag ($C7), setting quote ($D4) and insert ($D8) modes, and counting each time at the left column ($D3).  Outputs string characters via $FFD2, and waits for a key press via $FFE4.

This is a short program that can be studied.  I hope you find it useful and informative.  Enjoy!

Links:
  original (compact) strings.prg
  updated (one line) strings.prg
  source at github

Copyright (c) 2024 by David R. Van Wagner
MIT LICENSE

UPDATE: (September 3, 2024) compact version was too ugly for me.  Have since updated source to display one string per row of the screen, with an option (POKE 951, 96) to revert to compact functionality.   See updated links above.

Sunday, June 2, 2024

BANKTEST for C64

While adding banking support to my own C64 emulator back in the good 'ole days (April 14, 2020, maybe only good for hunkering down on retro stuff), I also wrote a test program to help verify the results.  This may help you visualize how you can access more RAM and ROM on the C64.

The program works by switching to the RAM only bank writing a signature high byte to four addresses, then cycles through the standard list of banks reading the value at those locations.  Of course the first line for bank zero shows the bytes as expected.  But the other banks tell a different story.

A000-BFFF is BASIC ROM.   Appears ROM is active in banks 3 & 7 only, otherwise is RAM.

C000-CFFF is always RAM.

D000-DFFF is usually I/O (banks 5-7) including color RAM at D8000 (notice the high nibble changes in this run).  May also appear as RAM (banks 0 & 4), CHAR ROM (banks 1-3).

E000-FFFF is BASIC ROM (banks 2, 3, 6, 7), otherwise RAM (banks 0, 1, 4, 5).

It is interesting to see the similarities and differences in this chart.

The key code to switching banks includes

        sei

        lda $01

        and #$f8

        ora #bank_selection

        sta $01

        rts

Only clear the interrupt flag (cli instruction) once you have returned to the normal bank (7) so IRQ vectors and the KERNAL/BASIC ROMs will work as expected.

I have also color encoded the banks in this chart to represent their effects:

Links

Sunday, May 26, 2024

LCD version of 6502 emulators ported to Windows

 

LCDs and Windows too!

Now the c-simple-emu6502-cbm unified branch that works with LCD systems has been ported to Windows!  This is an emulator that includes a feature to switch between various popular Commodore 8-bit models from the BASIC prompt.

You may ask yourself, hey self, wasn't Windows already a supported system?  And you could answer, yes self, it was.  But only in text mode.  If you wanted to run Commodore BASIC from a command prompt, yes you could do that.  If you wanted to run this emulator with the nifty "GO 128" command in a graphical environment you were required to use those smallish LCDs (well the 7" isn't too smallish).

Now, by porting this C++ project back to Windows again, using GUI elements, it can now look more like a Commodore.  The fully resizable window, and keyboard support make it feel like you have a Commodore right in front of you.  You virtually do!

For now, you need to compile the project in Visual Studio 2022 (Community Edition should work just fine).  It probably also works from Visual Code, but I haven't attempted that yet.

Dependencies include a roms folder (see README.md), optional disks/drive8.d64, and optional disks/drive9.d64

The purpose of this is to ease development of new features, utilizing the feature rich Visual Studio IDE including debug support.

The benefits to other users include being able to test drive the project in an environment they already have - their existing Windows desktop or VM.   And if you love it and think you may enjoy a portable version, you can then invest your dollars into an LCD solution via various online retail websites.   There may even be a search engine out there to help you too.

Are you keeping up with Commodore?  Happy computing!  Spend that money wisely.

Thursday, May 9, 2024

Running SWEET16, Steve Wozniak's "The Dream Machine" from WozMon


The story goes that Steve Wozniak was running out of space in Apple Integer BASIC, and out of necessity, determination, and will power, developed SWEET16 to do 16-bit operations in a more compact fashion.  There is already a great article on SWEET16, the interpretive processing 16-bit supplement to 6502 machine language programs, over at 6502.org.  The article tells the history, instructs how to port, and provides a tutorial on how to use it.  (And see article on Wikipedia, and Steve Wozniak's 1977 article in Byte magazine).

My article will follow the steps to produce a binary to run on my minimal 6502 with MC6850 UART, and run through a few examples to use it together with the Apple-1 Hex Monitor, ported from listings included in the Apple-1 Operation Manual (1976).  The Hex Monitor (or WozMon as people generally refer to it) is the original 256-byte ROM included with the Apple-1 computer.  It only needed to include display memory, edit memory, and run from memory operations to initiate control of that computer.

This article and efforts are inspired by videos produced by Ben Eater and his 6502 breadboard computer.  I wanted to do something similar, and followed instructions he provided to do something similar with my 6502 emulator, but simpler.   

I already had a 6502 emulator.  One version is in C++, is very cross-platform (Windows, Linux, Mac, Arduino, STM32, etc.).  But I had focused on Commodore emulation to match the computers I grew up with learning to program.  While that is working well, it is using Commodore ROMs and some I/O emulation. 

Also inspirational are similar videos produced by Michael Cartwright for his Hopper development environment and 6502 breadboard and PCB computer, inspired by Ben Eater's 6502 breadboard computer.  Michael (sillycowvalley on github) uses the MC6850 UART instead of the MC6821 PIA used in Apple-1, or MOS6522 VIA or MOS6551 UART used by Ben Eater.

I surely didn't want to bit bang serial, and wanted it as simple as possible.  Reviewing resources on the web, including datasheets, it was apparent the MC6850 has an advantage of being rather minimalistic.  It has one data register (read/write), one control register (write), and one status register (read).  While originally intended for use with 6800 series microprocessors, it can be used with others.  Only caveat is that the status is not designed for the 6502 BIT instruction.  But the advantage is that it doesn't have a status bug like the 6551 which intended to replace it.

So, I sat down and added a minimal emulation profile to my emulator including configurable RAM/ROM, and I/O address for the MC6850.  My initial implementation supports polling but not interrupts, which is fine for our purposes today.  It does not include a parallel I/O chip, so no hooking up virtual LEDs.  Wait, what?  Oh yeah, we don't need those (yet?), we exclusively have a terminal console.   But that also means we don't have a way to load or save programs.

Also imagine 60K RAM and 4K ROM here (oops!)

I ported WozMon to the 6502/MC6850 minimum profile so it will serve as our launching off point, similar to how it was utilized on the Apple-1.  Porting required changing the assembler syntax to match my 6502 assembler of choice (ACME), especially note that all the hex values in the file should include # for immediate mode (if extracting from Usenet article instead of Byte article), DFB must stand for define byte, and you do need to include some save/restore register routines.

An advantage of having a minimal system unlike Commodore, is that the 32 consecutive zero-page bytes necessary for SWEET16 are guaranteed to be available because it is a minimal system, addresses are not used by IRQ routines, keyboard handlers, timers, KERNAL I/O, etc.

Steps

1. Clone (or download Zip of) the emulator c-simple-6502-cbm.  Note it is not necessary to gather the Commodore ROMs this time around, because we don't need them.

2. Compile using Visual Studio, or make/gcc (Makefile included), or similar.

3. Look for wozmon.bin in the roms/minimal folder (its ported source is in child src folder).

4. Launch the minimal profile

    c-simple-6502-cbm.exe 1 roms/minimal/wozmon.bin

Now WozMon should be running.  You can review the Apple-1 Operation Manual (1976) for more detailed instructions on how to use WozMon.  But if you're quick, you can follow along with the required inputs here.

5. Paste SWEET16 binary into WozMon.   See copyright at start of article, included here for educational purposes, trusting this is fair use and for your own personal use.  Not for commercial use.

# SWEET16 compiled for EE80 start address
EE70: 20 EA EE 68 85 1E 68 85
EE78: 1F 20 7F EE 4C 79 EE E6
EE80: 1E D0 02 E6 1F A9 EF 48
EE88: A0 00 B1 1E 29 0F 0A AA
EE90: 4A 51 1E F0 0B 86 1D 4A
EE98: 4A 4A A8 B9 C8 EE 48 60
EEA0: E6 1E D0 02 E6 1F BD CB
EEA8: EE 48 A5 1D 4A 60 68 68
EEB0: 20 F6 EE 6C 1E 00 B1 1E
EEB8: 95 01 88 B1 1E 95 00 98
EEC0: 38 65 1E 85 1E 90 02 E6
EEC8: 1F 60 00 F7 02 9B 0B 9C
EED0: 23 AD 14 B0 45 B7 4F BE
EED8: 2D C7 59 D0 83 DB 6C 03
EEE0: 31 E6 6E 91 1C E5 63 E5
EEE8: E5 E5 85 20 86 21 84 22
EEF0: 08 68 85 23 D8 60 A5 23
EEF8: 48 A5 20 A6 21 A4 22 28
EF00: 60 10 B3 B5 00 85 00 B5
EF08: 01 85 01 60 A5 00 95 00
EF10: A5 01 95 01 60 A5 00 81
EF18: 00 A0 00 84 1D F6 00 D0
EF20: 02 F6 01 60 A1 00 85 00
EF28: A0 00 84 01 F0 ED A0 00
EF30: F0 06 20 64 EF A1 00 A8
EF38: 20 64 EF A1 00 85 00 84
EF40: 01 A0 00 84 1D 60 20 24
EF48: EF A1 00 85 01 4C 1D EF
EF50: 20 15 EF A5 01 81 00 4C
EF58: 1D EF 20 64 EF A5 00 81
EF60: 00 4C 41 EF B5 00 D0 02
EF68: D6 01 D6 00 60 A0 00 38
EF70: A5 00 F5 00 99 00 00 A5
EF78: 01 F5 01 99 01 00 98 69
EF80: 00 85 1D 60 A5 00 75 00
EF88: 85 00 A5 01 75 01 A0 00
EF90: F0 E9 A5 1E 20 17 EF A5
EF98: 1F 20 17 EF 18 B0 0E B1
EFA0: 1E 10 01 88 65 1E 85 1E
EFA8: 98 65 1F 85 1F 60 B0 EC
EFB0: 60 0A AA B5 01 10 E8 60
EFB8: 0A AA B5 01 30 E1 60 0A
EFC0: AA B5 00 15 01 F0 D8 60
EFC8: 0A AA B5 00 15 01 D0 CF
EFD0: 60 0A AA B5 00 35 01 49
EFD8: FF F0 C4 60 0A AA B5 00
EFE0: 35 01 49 FF D0 B9 60 A2
EFE8: 18 20 64 EF A1 00 85 1F
EFF0: 20 64 EF A1 00 85 1E 60
EFF8: 4C AE EE 00 00 00 00 00

Note: SWEET16 entry point for this port is $EE70, and the operations are in a single page $EF01-$EFFA.   A save registers routine is at $EEEA and restore registers is at $EEF6.   Zero page usage is $00-$1F for the SWEET16 registers, and $20-$23 for saving 8-bit registers.

6. Let's try it out.  Start by pasting the following to enter a program at 

1000: 20 00 FE A9 2A 20 70 EE 
1008: 11 12 34 12 56 78 21 A2
1010: 33 00 8D F8 FF 00

Which is equivalent to

20 00 FE JSR $FE00
A9 2A    LDA #$2A
20 70 EE JSR $EE70
11 12 34 SET R1,$3412
12 56 78 SET R2,$7856
21       LD  R1 
A2       ADD R2
33       ST  R3
00       RTN
8D F8 FF STA $FFF8
00       BRK

JSR $EE70 switches to SWEET16 interpretation, and these are SWEET16 instructions through RTN, before being back in 6502.  The vectors are set such that a BRK will return to WozMon. ($FE00 is my specific UART initialization routine for MC6850, and storing a byte to $FFF8 will send it across the UART).

All this program does is set the R1 and R2 16-bit registers to constant values, the LD instruction loads the 16-bit accumulator from R1, then ADD R2 adds R2 to the accumulator, and the result is stored in R3 by the ST instruction.   RTN returns to normal 6502 operation.

7. To run the program, enter the following into WozMon:

1000R

8. Display the results by entering

0.1FR

From the last two steps the output should look something like the following (blank lines added for separation)

1000R

1000: 20*\


0.1F

0000: 68 AC 12 34 56 78 68 AC
0008: 00 00 00 00 00 00 00 00
0010: 00 00 00 00 00 00 00 00
0018: 00 00 00 00 00 06 12 10

And the accumulator (R0) at addresses 0 and 1 now has the value $AC68 which appears to be the sum of the other two 16-bit values, with a copy also stored at R3 (addresses 6/7).  The asterisk is printed to demonstrate registers being saved/restored and 6502 operation returning to normal.

That's just a quick example.   Hopefully you've got a little taste of WozMon and SWEET16. 

Example run of SWEET16

But that's not all!  

I made a Commodore port of WozMon, so why not also port SWEET16 to Commodore and run it there too?

# Commodore port of SWEET16
1540: 85 22 86 23 84 24 08 68
1548: 85 25 d8 60 a5 25 48 a5
1550: 22 a6 23 a4 24 28 60 00
1558: 00 00 00 00 00 00 00 00
1560: 00 00 00 00 00 00 00 00
1568: 00 00 00 00 00 00 00 00
1570: 00 00 00 00 00 00 00 00
1578: 00 00 00 00 00 00 00 00
1580: 20 40 15 68 85 7e 68 85
1588: 7f 20 8f 15 4c 89 15 e6
1590: 7e d0 02 e6 7f a9 16 48
1598: a0 00 b1 7e 29 0f 0a aa
15a0: 4a 51 7e f0 0b 86 7d 4a
15a8: 4a 4a a8 b9 d8 15 48 60
15b0: e6 7e d0 02 e6 7f bd db
15b8: 15 48 a5 7d 4a 60 68 68
15c0: 20 4c 15 6c 7e 00 b1 7e
15c8: 95 61 88 b1 7e 95 60 98
15d0: 38 65 7e 85 7e 90 02 e6
15d8: 7f 60 00 f7 02 9b 0b 9c
15e0: 23 ad 14 b0 45 b7 4f be
15e8: 2d c7 59 d0 83 db 6c 03
15f0: 31 e6 6e 91 1c e5 63 e5
15f8: e5 e5 00 00 00 00 00 00
1600: 00 10 c3 b5 60 85 60 b5
1608: 61 85 61 60 a5 60 95 60
1610: a5 61 95 61 60 a5 60 81
1618: 60 a0 00 84 7d f6 60 d0
1620: 02 f6 61 60 a1 60 85 60
1628: a0 00 84 61 f0 ed a0 00
1630: f0 06 20 64 16 a1 60 a8
1638: 20 64 16 a1 60 85 60 84
1640: 61 a0 00 84 7d 60 20 24
1648: 16 a1 60 85 61 4c 1d 16
1650: 20 15 16 a5 61 81 60 4c
1658: 1d 16 20 64 16 a5 60 81
1660: 60 4c 41 16 b5 60 d0 02
1668: d6 61 d6 60 60 a0 00 38
1670: a5 60 f5 60 99 60 00 a5
1678: 61 f5 61 99 61 00 98 69
1680: 00 85 7d 60 a5 60 75 60
1688: 85 60 a5 61 75 61 a0 00
1690: f0 e9 a5 7e 20 17 16 a5
1698: 7f 20 17 16 18 b0 0e b1
16a0: 7e 10 01 88 65 7e 85 7e
16a8: 98 65 7f 85 7f 60 b0 ec
16b0: 60 0a aa b5 61 10 e8 60
16b8: 0a aa b5 61 30 e1 60 0a
16c0: aa b5 60 15 61 f0 d8 60
16c8: 0a aa b5 60 15 61 d0 cf
16d0: 60 0a aa b5 60 35 61 49
16d8: ff f0 c4 60 0a aa b5 60
16e0: 35 61 49 ff d0 b9 60 a2
16e8: 18 20 64 16 a1 60 85 7f
16f0: 20 64 16 a1 60 85 7e 60
16f8: 4c be 15

This SWEET16 entry point for Commodore changed to $1580 so the sample program has to change to call this entry point instead, to call $FFD2 for screen output instead of using the UART, and jump to WozMon entry at end instead of BRK.   Note that this Commodore port puts the SWEET16 registers at $60 (instead of $00) in zero page.   The Commodore port was trivial, disassembly will show there's nothing secret going on, mostly moving around stuff in zero page, and moving the save/load registers code.

1000: A9 2A 20 80 15 11 12 34
1008: 12 56 78 21 A2 33 00 20
1010: D2 FF 4C 00 14
 
Vic-20 running WozMon and SWEET16

C64 running WozMon and SWEET16

It appears there's a bug restoring the registers.  That is not an asterisk!!!   But an underscore.   Exercise left for another day...   Update: I had replaced the call to UART_INIT from the other system with starting SWEET16 followed by 6502 code.  Bad, so bad (see screenshot for bad code).  Have since updated the sample program to be correct.   Disassembling here to double check.   The asterisk is now showing up fine!  Would have been doing some crazy stuff interpreting 6502 opcodes as SWEET16.

A9 2A    LDA #$2A
20 80 15 JSR $1580
11 12 34 SET R1,$3412
12 56 78 SET R2,$7856
21       LD  R1 
A2       ADD R2
33       ST  R3
00       RTN
20 D2 FF JSR $FFD2
4C 00 14 JMP $1400