Handheld PC based on the original 6502 CPU that fits into a pocket.
- 12 digit 16-segment LED display (DL1414),
- optional 8x2 standard LCD (not supported yet in FW),
- 24 button keyboard,
- 8 KiB of ROM and 8 KiB of RAM,
- I2C 24xx EEPROM memory (16 bit addressing, up to 64 KB),
- built-in Li-Po power supply, charger and visual voltage indicator,
- monitor FW that allows memory editing and running user programs,
- expansion slot with 5 chip selects (up to 40 KiB of external I/O and/or memory),
- based on my Pocket65 project (github.com/agkaminski/Pocket65) with a partial compability.
Start | End | Description |
---|---|---|
0x0000 | 0x1FFF | RAM |
0x2000 | 0x3FFF | External 1 |
0x4000 | 0x5FFF | External 2 |
0x6000 | 0x7FFF | External 3 |
0x8000 | 0x9FFF | External 4 |
0xA000 | 0xBFFF | External 5 |
0xC000 | 0xC3FF | Keyboard |
0xC400 | 0xC7FF | Screen |
0xC800 | 0xCBFF | NMI ack |
0xCC00 | 0xCFFF | 4 bit GPIO |
0xE000 | 0xFFFF | ROM |
Pocket265 simulator is there to make FW developement easier, but it can be also used to get a feel for the computer usage. Only UART is not simulated. It uses simak65 simulator code.
$ ./pocket265-sim [OPTIONS]
where options are:
- -c: path to the computer ROM (obligatory),
- -f: simulated CPU frequency, from 0 (max speed, no throttling) to 20000000 (Hz),
- -r: simulated RAM size in bytes,
- -e: simulated EEPROM file (will be updated after end of the simulation, if write is performed!),
- -h: usage.
To run the simulation first build and install simak65:
$ (git submodule update --init && cd simak65 && make all && sudo make install)
then build the FW:
$ (cd fw && make all)
then build the simulator:
$ (cd sim && make all)
In the sim/
directory is a script that starts the simulator with memory initialized with Pocket265 firmware - runsim.sh
. To run the simulator:
$ cd sim $ ./runsim.sh
Simulator is started and after boot sequence the main screen is presented in the terminal:
[MON 0800 >00] [ F1 ][ F2 ][ F3 ][ F4 ] [ C ][ D ][ E ][ F ] [ 8 ][ 9 ][ A ][ B ] [ 4 ][ 5 ][ 6 ][ 7 ] [ 0 ][ 1 ][ 2 ][ 3 ] [ INC ][ DEC ][ SEL ][ GO ]
Keyboard keys presses are redirected to the simulated Pocket265 computer. Key mapping is presented below:
Keyboard | Pocket265 |
---|---|
0-9, a-f | hex keyboard |
h | INC |
j | DEC |
k | SEL |
l | GO |
u | F1 |
i | F2 |
o | F3 |
p | F4 |
First welcome splash-screen is displayed:
POCKET265
After that version and copyright information is scrolled over and a memory test is performed:
6144 B FREE
By default 6144 bytes are free (2 KiB are reseved for ROM), the memory can be expanded by expansion slot card.
After 1 seconds computer proceeds to the main mode of operation:
MON 0800 >00
In the main mode and byte modification mode selected (>
pointing to the memory value) memory editing is possible. To modify the memory content press a key 0
to F
. The old value is then shifted 4 binary places to the left and new nibble is inserted at the youngest position. Previous 4 oldest bits are lost.
Example - entering 0xBA
at the current address:
We start with the desired memory cell selected (in this case the cell at address 0x0800
):
MON 0800 >00
press B
button to enter 0xB:
MON 0800 >0B
then press A
button to finish entering the byte:
MON 0800 >BA
Done!
The address can be modified in two ways:
To select a next or previous memory cell press INC
or DEC
button respectively. The address will be incremented/decremented by one.
Big leaps through memory space are not very convenient using incrementation and decrementation. One can change the address very similar to changing a memory value. To enter the address editing mode press SEL
key. <
will point to the address to confirm mode selection:
MON 0800< 00
In this mode address can be modified the same way memory can be modified - when key 0-F
is pressed the old address is shifted 4 bits to the left and new value is inserted at the youngest position.
To exit the address editing mode (and return to the memory value editing mode) press SEL
key again.
To start a user program provide its entry point in the address field (using the address edition mode) and press GO
key.
F1
key toggles auto-increment mode. When active it is indicated by a +
sign next to the address:
MON 0800+>00
If this mode is active then when a whole byte is entered (i.e. two 0-F
keys presses) the address will be incremented automatically. This mode is very useful for a binary program listing input, as no additional key press between bytes inputs is needed.
F2
key displays monitor menu which contains additional ROM functions. To show a next item press INC
key, press DEC
for a previous one. To select an item press GO
.
Copy memory range. A destination address is an address currently set in the monitor. User is prompted for a source address and length (both inputed as 4 digit hexadecimal numbers).
Save data to the I2C memory. A source address is an address currently set in the monitor. User is prompted for a destination address on the device and length (both inputed as 4 digit hexadecimal numbers).
Load data from the I2C memory. A destination address is an address currently set in the monitor. User is prompted for a source address on the device and length (both inputed as 4 digit hexadecimal numbers).
Enable serial communication (available on the mini USB port via USB-UART bridge). 200 baud, 1 stop, no parity. Communication is very similar to pressing keys on the computer keyboard and it's mostly dedicated for scripting use. Each valid character is echoed back, data stream should be slow (i.e. sender should wait for an echo before sending a next character, as UART function is performed in software via bit-bang and it's half-duplex only). Valid characters:
0-9
,a-f
,A-F
- hex numbers to set address or data,@
- set mode to address editing mode,#
- set mode to data editing mode,!
- start program at current address.
Auto increment mode is always enabled for serial communication.
Display FW version (git hash/tag).
Clear user memory (set all bytes to 0).
User program examples are provided in the user/example
directory, the user program template is provided in the user
directory along with ROM calls user library and Makefile.
User is free to use whole memory, exluding:
Start | End | Description |
---|---|---|
0x00C0 | 0x00FF | ROM ZP area |
0x0100 | 0x01FF | HW stack |
0x0200 | 0x07FF | RAM for ROM usage |
0xC000 | 0xCFFF | HW handled by ROM |
Interrupt vectors are located in ROM area, so they cannot be modified by an application code. Monitor can redirect IRQ and NMI to user handlers - there are two ROM calls to register an user interrupt handler:
svc_irqRegister
- register a IRQ handler,svc_nmiRegister
- register a NMI handler.
The handler address is passed in X (low byte) and Y (high byte) registers.
Use RTS
instruction to return from the handler insted of RTI
- monitor handles return from the interrupt part.
When X and Y registers are used to pass 16-bit value, X holds low byte and Y holds high byte. ROM calls do not destroy unrelated registers/memory contents.
Register a user IRQ handler and enable interrupts.
- Arguments: X, Y - handler address.
- Returns: none.
Register a user NMI handler.
- Arguments: X, Y - handler address.
- Returns: none.
Displays an ASCII character on the screen.
- Arguments: A - character.
- Returns: none.
Displays a null-terminated ASCII string on the screen.
- Arguments: X, Y - string address.
- Returns: none.
Display a hex byte on the screen.
- Arguments: A - byte.
- Returns: none.
Print a 16-bit number stored in registers X and Y.
- Arguments: X, Y - number.
- Returns: none.
Print a 16-bit number in registers X and Y as a unsigned decimal.
- Arguments: X, Y - number.
- Returns: none.
Print a 16-bit number in registers X and Y as a signed decimal.
- Arguments: X, Y - number.
- Returns: none.
Fetch a 16-bit unsigned number from the user (hexadecimal input).
- Arguments: X, Y - ASCII string (prompt).
- Returns: X, Y - number.
Fetch a 16-bit unsigned number from the user (decimal input).
- Arguments: X, Y - ASCII string (prompt).
- Returns: X, Y - number.
Fetch a key code, block until a new key is pressed.
- Arguments: none.
- Returns: A - key code.
Fetch a current key code.
- Arguments: none.
- Returns: A - key code.
Fetch a current miliseconds timer value (one byte).
- Arguments: none.
- Returns: A - jiffies.
Fetch a current seconds timer value (one byte).
- Arguments: none.
- Returns: A - seconds.
Sleep for 0-255 ms.
- Arguments: A - time (ms).
- Returns: none.
Sleep for 0-255 s.
- Arguments: A - time (s).
- Returns: none.
Disable NMI.
- Arguments: none
- Returns: none.
Restart NMI.
- Arguments: none.
- Returns: none.
Free for non-commercial use and educational purposes. See LICENSE.md for details.