Apple 1 emulator

1st draft of a quick hacked apple one emulator based on arduino_6502 from miker00lz.
I am NOT at all a c programmer! Needs absolutely improvements.
Also apple 1 BIOS starts at F000 or FF00? Ram size is still old value from orig. project and should be set
to 4kb I think.

1st things seem to work despite that. I used arduino pro 328p 16M with 9600 8N1.

Link to orig. project:
http://forum.arduino.cc/index.php?topic=193216.0

Peter

a1.ino (913 Bytes)

cpu.c (25.5 KB)

Apple 1 ??? There were not very many of those ever sold.
For the Apple ][ ,
if you look in the "Red Book" technical manual,
you can see the full listing of the apple 2 system monitor code
and it starts at 0xf800

--- bill

Thx. But apple II are not of my interest right now :wink:

Anyway. Now with apple basic at 0xE000.

However. I have an issue that system hangs if I increase RAM size above orig. code 1536?!
(In cpu.h right at top lines: #define RAM_SIZE 1536)

Why? I would need 4096 for the apple 1.

Using arduino pro with Atmega328p (so has 8k SRam - right?)

Thx, Peter

a1.ino (952 Bytes)

cpu.c (49.3 KB)

328p only has 2k of ram.

--- bill

Arrgh. Thx. Somehow I was under the (false) meaning, the 328 had 8k sram..
Just tried same code (just RAM size set to 4096) on an arduino Mega 2560 - and it works!
Should work on normal Mega as well, since 1280 has also 8k ram.

:slight_smile:

Now I have a working apple 1 emulator. :grin:

I think I still have to look in apple char vs. ascii char conversion.. but that may come next..

Thx, Peter

something like?

a1char = ((asciichar & 0x5f) - 0x20) ^ 0x20;

To convert from ascii code to 2513 character font index.

--- bill

'maybe' :o

I would like to find a comparison table (two tables aside) or something similiar..

How did you arrive at above code?

I need to convert chars coming from emulated apple 1 prior to be send out via serial and
2nd I (probably?) need to convert incoming chars from serial prior to give them to emulated apple 1 environment. Right?

thx, Peter

petersieg:
'maybe' :o

I would like to find a comparison table (two tables aside) or something similiar..

How did you arrive at above code?

You could use a table but that is unnecessary given the similarity in the mappings.
There is no need to waste the code code space for a table lookup when they can
easily be calculated.
From the 2513 character map I was able to find (from a 2513 datasheet),
it appeared that the 2513 character set has the characters in a similar order as ASCII.
Look at the ASCII characters from 0x20 to 0x5f compared to the characters in the 2513.
The difference is that first and send group of 32 characters are flipped.
i.e. the 2513 flipped them.

To me it looks like the 2513 screwed up and mis mapped bit 4 of addressing
by accidentally flipping it. I see no need to have incorrectly mapped the characters
to the ascii set.

The 2513 only contains a partial mapping.

It also has no data for the fist 32 characters since it starts with "@".

The 2513 characters stop at ASCII 0x5f


So to map between them all you have to do is take all that into consideration.

To get from ascii to 2513 you first mask with 0x5f
which essentially converts all the lower case to upper case.
A few characters get miss mapped like ` { | } ~ DEL but then those
don't exist in the 2513. Those will get mapped to @ [ \ ] ^ _

You then subtract 0x20 to drop the ascii code down to account for the
special characters.

To handle flipping of the two groups of 32 characters all you have to do is flip
bit 4 of the character code address.

And that is how you end up with

a1char = ((asciichar & 0x5f) - 0x20) ^ 0x20;

To go the other way,
You would flip the address bit then add the 0x20.

asciichar = (a1char ^ 0x20) + 0x20;

--- bill

Hmm..Nop. Doesn'work

  void serout(uint8_t val) {
    //Serial.print(val, HEX);
    //Serial.println();  
    tmpkey = (val ^ 0x20) + 0x20;
    Serial.write(tmpkey);
  }
  uint8_t isakey() {
    if (Serial.available()) iskey  = 0x80;
    else iskey = 0;
    return(iskey);
  }
  uint8_t getkey() {
    tmpkey = Serial.read();
    curkey = ((tmpkey & 0x5f) - 0x20) ^ 0x20;
    return(curkey);
  }
  void clearkey() {
    curkey = 0;
  }

I got some scruwed up chars:

apple 1 emulator

œMFxxx

F is fine.
x is some other char but should be 0

Peter


Not sure what you are needing/wanting/trying to do.
ASCII is ASCII and I'm guessing that the apple 1 did everything in memory in ASCII
(The apple 2 did)
The funkiness is how to get from an ASCII value to a 2513 character code index value
which is at the very low level hardware level.
The conversions I gave are to go back and forth between an ascii code to a 2513 glyph index value.

In an emulator, I'm not sure that any sort of mapping like this would be necessary.

It should be easy to tell.

print the hex value for a few of the apple 1 characters without any modifications and look at the values
to see if they match the character for ASCII.

Yes. Maybe this is really not required at all..

I now just mapping incoming lower case a-z to upper case A-Z:

    // make a-z => A-Z
    if ((curkey >= 97) && (curkey <= 122)) curkey = curkey - 0x20;

I will leave the emulator as it is for now and will do some more testing with existing programs (asm & basic).

Peter

a1.ino (1.02 KB)

cpu.c (49.3 KB)

petersieg:
'maybe' :o

I would like to find a comparison table (two tables aside) or something similiar..

How did you arrive at above code?

I need to convert chars coming from emulated apple 1 prior to be send out via serial and
2nd I (probably?) need to convert incoming chars from serial prior to give them to emulated apple 1 environment. Right?

thx, Peter

No that is not necessary. The Apple 1 just uses ASCII (uppercase only). The role of the GI 2513 is to convert a character code to a bitmap shown on the video display. For characters coming in via the keyboard the 2513 is not involved therefore.
Since your emulator does not generate a video display you can for now ignore the 2513 and all the video display hardware present in the Apple 1.

Jup.
Just loaded the 30th aniverary demo. After setting teraterm to 40 chars wide screen,
it looks like it is working ok :wink:

Does someone has some links to apple 1 software/programs.

I found already sb-projects with a1 assembler.

I also found startrek.bas - but that seems to need more the 4k ram (with basic running).
(Gives out of MEM msg from basic interpreter)

Peter

Find attached the 30th aniversary HEX and lander.bas in the ZIP.
These are working. Just put your terminal emulation in 40 char wide mode.
startrek.bas has syntax errors at lines 230+440 and gives out of mem errors even on a due with 32k Ram?!
codebreaker maybe needs a special terminal emulation?

If you have links to make software in either HEX or basic ascii text format, please let me know.

BTW: Runs fine on arduino due with 32768 ramsize.

Peter

apple1_soft.zip (5.48 KB)

Update.
Now included: a1 assembler (c) 9/2006 San Bergmans released as freeware (Thanks!)
Link: http://www.sbprojects.com (Visit his great side!)

Switch between apple basic at 0xE000 and a1 assembler at 0xE000 is done by Pin 2.
Open/High = apple basic. GND/Low = a1 assembler
Switch is only read at startup of system/or reset.

I also included: 23-matches and lunar lander, both basic programs and microchess to be loaded into this apple 1 emulation.

I currently develop this on a arduino due. Mega should still be fine with 4k ram.

Peter

a1.ino (1.65 KB)

cpu.c (70.1 KB)

a1-2.JPG

apple1-sw2.zip (6.22 KB)

Fix for Terminal endline handling,

in file a1.ino replace

void serout(uint8_t val) {
    //Serial.print(val, HEX);
    //Serial.println();
    Serial.write(val);
  }

by

void serout(uint8_t val) {
    if (val == 13) {
      Serial.println();
      }
    else {
      Serial.write(val);
      }
  }

though i'll publish it here too, cause i have already posted about it on 6502.org

I've been toying around the code and implemented an MMU, as there is no Cassette interface a C000 and no real need for it i bumped the RAM straight to CFFF the memory map is designed like thsi:

0000-0FFF base 4K RAM
1000-8FFF 32K or 16K bank 1 & 2
9000-CFFF 16K bank area (316K RAM bank, 116K ROM bank with EHBASIC ) switch register at D020
D000-DFFF PIA I/O area, the MMU is implemented here at D020 & D021
E000-EFFF either BASIC 1 or ASM 1 as peter version but switch at runtime with D021 no need to ground any pin
F000-FFFF HIGH ROM area, APPLE 2 monitor & Apple 2 mini assembler 256 bytes lower than in the Apple 2
& WOZ monitor at FF00

demo video on youtube: APPLEIDUE 84K RAM - YouTube

big-a1.zip (30.7 KB)

another UPDATE

the change are as follow

implementation of memroy read & write a byte at a time to the banks without maping them, they still can be mapped with D020 as before

D02A LOWBYTE address (bank relative)
D02B HIGHBYTE address (bank relative)
D02C BANK TO TRANFER TO/FROM
D02D DATA TO/FROM THE BANK
D02E DIRECTION -> FF=WRITE | FE = READ

WRITING FE at DFFF trigger a cpu reset, FF quite the emulator in my linux console version/does nothing on the arduino

EHBASIC example that copy from the EHBASIC ROM BANK to the First 16K RAM bank
to run EHBASIC from it's ROM BANK in woz monitor type

D020: 04
9000R

press C for coldstart
press enter ehbasic should detect the 36K ram by itself
then type in

5 PRINT "COPYING 16K BYTE PER BYTE"
6 PRINT "PLEASE WAIT..."
10 FOR HB = 0 TO 64 : FOR LB = 0 TO 255
20 POKE 53290,LB: POKE 53291,HB: POKE 53292,4: POKE 53294,254
25 A = PEEK(53293)
30 POKE 53290,LB: POKE 53291,HB: POKE 53292,0: POKE 53294,255
35 POKE 53293,A
40 NEXT LB
45 PRINT (HB+1)*256;" BYTES"
50 NEXT HB

on the Arduino this is slow ass, the EHBASIC is 10706 Bytes long, you can hit ctrl+C after 10752 BYTES and return to the woz monitor, swiitch the first 16K ram bank back and run EHBASIC again like this

CALL 65311
D020: 00
9000R

type w for warm start, our copy program should sitll be in the memory in the 36 firsts K; EHBASIC now run from ram bank 1

big-a1.zip (30.9 KB)