Skip to content

Commit

Permalink
Merge pull request #141 from venomix666/nano6502
Browse files Browse the repository at this point in the history
Port to the nano6502
  • Loading branch information
davidgiven authored Aug 5, 2024
2 parents 265d801 + 176ddba commit c3c7e17
Show file tree
Hide file tree
Showing 12 changed files with 1,620 additions and 0 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ to the 6502. So far it runs on:

- Olimex' neo6502 6502-based computer.

- nano6502 6502-based SoC for the Tang Nano 20K FPGA board; TPA is 55kB.

Unlike the original, it supports relocatable binaries, so allowing unmodified
binaries to run on any system: this is necessary as 6502 systems tend to be
much less standardised than 8080 and Z80 systems. (The systems above all load
Expand All @@ -57,6 +59,7 @@ No, it won't let you run 8080 programs on the 6502!
<a href="doc/oric.png"><img src="doc/oric.png" style="width:40%" alt="CP/M-65 running on an Tangerine Oric 1"></a>
<a href="doc/sorbus.png"><img src="doc/sorbus.png" style="width:40%" alt="CP/M-65 running on the Sorbus Computer"></a>
<a href="doc/neo6502.png"><img src="doc/neo6502.png" style="width:40%" alt="CP/M-65 running on the Olimex neo6502"></a>
<a href="doc/nano6502.png"><img src="doc/nano6502.png" style="width:40%" alt="CP/M-65 running on the nano6502"></a>
</div>


Expand Down Expand Up @@ -309,6 +312,22 @@ the same time.
- The console is 53x30. It has a SCREEN driver.
### nano6502 notes
- The [nano6502](https://github.com/venomix666/nano6502/) is a 65C02-based SoC for the Tang Nano 20K FPGA board.
- The CPU is running at 25.175 MHz (i.e. the pixel clock).
- It is using CPMFS directly on the microSD-card, with 15x1Mb partitions (drives `A` to `O`).
- The text output is over HDMI, with 640x480 video output and a 80x30 console. It has a SCREEN driver.
- The input is currently using the built in USB serial port. This way, this port can be run with only the Tang Nano 20K board without any specific carrier board.
- To use, write the `nano6502.img` file into the SD-card using `dd` or your preferred SD-card image writer. If you are updating the image and want to preserve the data on all drives except `A`, write the `nano6502_sysonly.img` instead.
- User area 1 on drive `A` contains utilities for setting the text and background colors, and a demo application which blinks the onboard LEDs.
### Supported programs
Commands include `DUMP`, `STAT`, `COPY`, `SUBMIT`, `ASM`, `QE` and `BEDIT` plus
Expand Down
2 changes: 2 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
"vic20.d64": "src/arch/commodore+vic20_diskimage",
"x16.zip": "src/arch/x16+diskimage",
"sorbus.zip": "src/arch/sorbus+diskimage",
"nano6502.img": "src/arch/nano6502+diskimage",
"nano6502_sysonly.img": "src/arch/nano6502+sysimage",
},
deps=[
"tests"
Expand Down
Binary file added doc/nano6502.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions src/arch/nano6502/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from build.ab import normalrule
from tools.build import mkdfs, mkcpmfs
from build.llvm import llvmrawprogram
from config import (
MINIMAL_APPS,
MINIMAL_APPS_SRCS,
BIG_APPS,
BIG_APPS_SRCS,
SCREEN_APPS,
PASCAL_APPS,
)

llvmrawprogram(
name="nano6502",
srcs=["./nano6502.S"],
deps=["include", "src/lib+bioslib"],
linkscript="./nano6502.ld",
)

mkcpmfs(
name="cpmfs",
format="generic-1m",
items={"0:ccp.sys@sr": "src+ccp",
"1:colorfg.com": "src/arch/nano6502/utils+colorfg",
"1:colorbg.com": "src/arch/nano6502/utils+colorbg",
"1:ledtest.com": "src/arch/nano6502/utils+ledtest"}
| MINIMAL_APPS
| MINIMAL_APPS_SRCS
| BIG_APPS
| BIG_APPS_SRCS
| SCREEN_APPS
| PASCAL_APPS,
)

mkcpmfs(
name="emptycpmfs",
format="generic-1m",
items="",
)

normalrule(
name="diskimage",
ins=[
".+cpmfs",
".+emptycpmfs",
".+nano6502",
"src/bdos",
],
outs=["nano6502.img"],
commands=["rm -f {outs[0]}","./src/arch/nano6502/buildimage.py"],
label="IMG",
)

normalrule(
name="sysimage",
ins=[
".+cpmfs",
".+nano6502",
"src/bdos",
],
outs=["nano6502_sysonly.img"],
commands=["rm -f {outs[0]}","./src/arch/nano6502/buildsysimage.py"],
label="IMG",
)

114 changes: 114 additions & 0 deletions src/arch/nano6502/buildimage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/python3

import sys
import os

bootsector_size = 512
bdos_offset = 512*256
cpmfs_offset = 512*256
cpmfs_size = 1024*1024

bios_filename = '.obj/src/arch/nano6502/+nano6502/+nano6502'
bdos_filename = '.obj/src/bdos/+bdos/+bdos'
cpmfs_filename = '.obj/src/arch/nano6502/+cpmfs/src/arch/nano6502/+cpmfs.img'
cpmfs_empty_filename = '.obj/src/arch/nano6502/+emptycpmfs/src/arch/nano6502/+emptycpmfs.img'
output_filename = '.obj/src/arch/nano6502/+diskimage/nano6502.img'

size = os.path.getsize(bios_filename)

outfile=open(output_filename, "wb")

# Write boot sector
# Boot sector format
# Magic number: 0x6E, 0x61, 0x6E, 0x6F
# SD sector to load - 4 bytes
# Number of pages to load - 1 byte
# Page to load data to - 1 byte
# Total 10 bytes
# Padding 502 bytes

bootsector_data = [0x6E, 0x61, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x01, 0x05, 0x03]

for d in bootsector_data:
outfile.write(d.to_bytes(1, "little"))

out=0
for i in range(bootsector_size - len(bootsector_data)):
outfile.write(out.to_bytes(1, "little"))

# Write BIOS

infile=open(bios_filename, "rb")
byte=infile.read(1)

# Write BIOS
while byte:
outfile.write(byte)
byte=infile.read(1)

padding = bdos_offset - size - bootsector_size
out = 0

while padding:
outfile.write(out.to_bytes(1,"little"))
padding = padding - 1;

infile.close()

# Write BDOS
size = os.path.getsize(bdos_filename)

infile = open(bdos_filename, "rb")

byte=infile.read(1)
while byte:
outfile.write(byte)
byte=infile.read(1)

padding = cpmfs_offset - size;
out = 0

while padding:
outfile.write(out.to_bytes(1,"little"))
padding = padding - 1;

infile.close()

# Write CPMFS
size = os.path.getsize(cpmfs_filename)

infile = open(cpmfs_filename, "rb")

byte=infile.read(1)
while byte:
outfile.write(byte)
byte=infile.read(1)

padding = cpmfs_size - size;
out=0
while padding:
outfile.write(out.to_bytes(1,"little"))
padding = padding - 1;

infile.close()

# Write empty drives B-O
for i in range(15):
size = os.path.getsize(cpmfs_empty_filename)

infile = open(cpmfs_empty_filename, "rb")

byte=infile.read(1)
while byte:
outfile.write(byte)
byte=infile.read(1)

padding = cpmfs_size - size;
out=0
while padding:
outfile.write(out.to_bytes(1,"little"))
padding = padding - 1;

infile.close()

outfile.close()
94 changes: 94 additions & 0 deletions src/arch/nano6502/buildsysimage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/python3

import sys
import os

bootsector_size = 512
bdos_offset = 512*256
cpmfs_offset = 512*256
cpmfs_size = 1024*1024

bios_filename = '.obj/src/arch/nano6502/+nano6502/+nano6502'
bdos_filename = '.obj/src/bdos/+bdos/+bdos'
cpmfs_filename = '.obj/src/arch/nano6502/+cpmfs/src/arch/nano6502/+cpmfs.img'
cpmfs_empty_filename = '.obj/src/arch/nano6502/+emptycpmfs/src/arch/nano6502/+emptycpmfs.img'
output_filename = '.obj/src/arch/nano6502/+sysimage/nano6502_sysonly.img'

size = os.path.getsize(bios_filename)

outfile=open(output_filename, "wb")

# Write boot sector
# Boot sector format
# Magic number: 0x6E, 0x61, 0x6E, 0x6F
# SD sector to load - 4 bytes
# Number of pages to load - 1 byte
# Page to load data to - 1 byte
# Total 10 bytes
# Padding 502 bytes

bootsector_data = [0x6E, 0x61, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x01, 0x05, 0x03]

for d in bootsector_data:
outfile.write(d.to_bytes(1, "little"))

out=0
for i in range(bootsector_size - len(bootsector_data)):
outfile.write(out.to_bytes(1, "little"))

# Write BIOS

infile=open(bios_filename, "rb")
byte=infile.read(1)

# Write BIOS
while byte:
outfile.write(byte)
byte=infile.read(1)

padding = bdos_offset - size - bootsector_size
out = 0

while padding:
outfile.write(out.to_bytes(1,"little"))
padding = padding - 1;

infile.close()

# Write BDOS
size = os.path.getsize(bdos_filename)

infile = open(bdos_filename, "rb")

byte=infile.read(1)
while byte:
outfile.write(byte)
byte=infile.read(1)

padding = cpmfs_offset - size;
out = 0

while padding:
outfile.write(out.to_bytes(1,"little"))
padding = padding - 1;

infile.close()

# Write CPMFS
size = os.path.getsize(cpmfs_filename)

infile = open(cpmfs_filename, "rb")

byte=infile.read(1)
while byte:
outfile.write(byte)
byte=infile.read(1)

padding = cpmfs_size - size;
out=0
while padding:
outfile.write(out.to_bytes(1,"little"))
padding = padding - 1;

infile.close()
outfile.close()
Loading

0 comments on commit c3c7e17

Please sign in to comment.