Merge branch 'main' into fullbyte

This commit is contained in:
Terence Boldt 2020-12-29 19:54:54 -05:00
commit fcf8e36eec
10 changed files with 291 additions and 208 deletions

12
Apple2/driver_assemble.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
ca65 Driver.asm --listing Driver.lst
ld65 Driver.o -o Driver.bin -t none
ca65 Firmware.asm -D STARTSLOT=\$c000 -o Slot0.o
ca65 Firmware.asm -D STARTSLOT=\$c100 -o Slot1.o --listing Firmware1.lst
ca65 Firmware.asm -D STARTSLOT=\$c200 -o Slot2.o --listing Firmware2.lst
ca65 Firmware.asm -D STARTSLOT=\$c300 -o Slot3.o --listing Firmware3.lst
ca65 Firmware.asm -D STARTSLOT=\$c400 -o Slot4.o --listing Firmware4.lst
ca65 Firmware.asm -D STARTSLOT=\$c500 -o Slot5.o --listing Firmware5.lst
ca65 Firmware.asm -D STARTSLOT=\$c600 -o Slot6.o --listing Firmware6.lst
ca65 Firmware.asm -D STARTSLOT=\$c700 -o Slot7.o --listing Firmware7.lst
ld65 Slot0.o Slot1.o Slot2.o Slot3.o Slot4.o Slot5.o Slot6.o Slot7.o -o Firmware.bin -t none

View File

@ -1,12 +0,0 @@
#!/bin/sh
ca65 Driver.asm --listing Driver.lst
ld65 Driver.o -o Driver.bin -t none
ca65 Firmware.asm -D STARTSLOT=\$c000 -o Slot0.o
ca65 Firmware.asm -D STARTSLOT=\$c100 -o Slot1.o
ca65 Firmware.asm -D STARTSLOT=\$c200 -o Slot2.o
ca65 Firmware.asm -D STARTSLOT=\$c300 -o Slot3.o
ca65 Firmware.asm -D STARTSLOT=\$c400 -o Slot4.o
ca65 Firmware.asm -D STARTSLOT=\$c500 -o Slot5.o
ca65 Firmware.asm -D STARTSLOT=\$c600 -o Slot6.o
ca65 Firmware.asm -D STARTSLOT=\$c700 -o Slot7.o
ld65 Slot0.o Slot1.o Slot2.o Slot3.o Slot4.o Slot5.o Slot6.o Slot7.o -o Firmware.bin -t none

View File

@ -1,11 +0,0 @@
ldx #$50 ;slot 5 for this test
start: lda #$80 ;set read flag low (ready to read)
sta $c08d,x ;bit 1 low for writing values
waitwl: lda $c08e,x ;bit 0 low for reading values
bmi waitwl ;wait for write flag low
jsr $fde3 ;print nibble of data
lda #$c0 ;set read flag high (done reading)
sta $c08d,x
waitwh: lda $c08e,x
bpl waitwh ;wait for write flag high
bmi start ;go around againg for next nibble

View File

@ -1,3 +0,0 @@
#!/bin/sh
ca65 test.asm
ld65 test.o -o test.bin -t none

View File

@ -13,8 +13,8 @@ This is an early stage project. Currently one board has been assembled and teste
1. DONE - Build initial prototype that reads/writes virtual hard drive
2. DONE - Create firmware to make the card a bootable device
3. DONE - Fix board with updated second prototype PCB
4. DONE - Add ProDOS clock driver
5. Add RPi terminal access
4. WORKING - Add ProDOS clock driver (real driver later, for now just directly sets values)
5. WORKING - Add RPi terminal access (does not keep context between commands yet)
6. Add web service call support
7. Proxy VNC connection, rendering as Apple II compatible graphics
8. Create new schematic/PCB with faster data transfer

View File

@ -1,14 +1,18 @@
package main
import (
"bytes"
"errors"
"fmt"
"os"
"os/exec"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/host"
"fmt"
"os"
"strings"
"time"
"errors"
)
var edgeTimeout time.Duration
var out_write gpio.PinIO
@ -31,23 +35,271 @@ var in_bit0 gpio.PinIO
const ReadBlockCommand = 1
const WriteBlockCommand = 2
const GetTimeCommand = 3
const ChangeDriveCommand = 4
const ExecCommand = 5
var debug bool = false
func main() {
host.Init()
initGpio()
if len(os.Args) == 3 && os.Args[2] == "--debug" {
debug = true
}
fmt.Printf("Starting Apple II RPi...\n")
fileName := os.Args[1]
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
if err != nil {
fmt.Printf("ERROR: %s", err.Error())
os.Exit(1)
}
for {
if debug {
fmt.Printf("Check for command\n")
}
command, err := readByte()
if err != nil {
//fmt.Printf("Timed out waiting for command\n")
} else {
switch command {
case ReadBlockCommand:
handleReadBlockCommand(file)
case WriteBlockCommand:
handleWriteBlockCommand(file)
case GetTimeCommand:
handleGetTimeCommand()
case ExecCommand:
handleExecCommand()
}
}
}
}
func handleReadBlockCommand(file *os.File) {
blockLow, _ := readByte()
blockHigh, _ := readByte()
buffer := make([]byte, 512)
var block int64
block = int64(blockHigh)*256 + int64(blockLow)
fmt.Printf("Read block %d\n", block)
file.ReadAt(buffer, int64(block)*512)
//dumpBlock(buffer)
readBlock(buffer)
}
func handleWriteBlockCommand(file *os.File) {
blockLow, _ := readByte()
blockHigh, _ := readByte()
buffer := make([]byte, 512)
var block int64
block = int64(blockHigh)*256 + int64(blockLow)
fmt.Printf("Write block %d\n", block)
writeBlock(buffer)
file.WriteAt(buffer, int64(block)*512)
file.Sync()
}
func handleExecCommand() {
fmt.Printf("Reading command to execute...\n")
linuxCommand,err := readString()
fmt.Printf("Command to run: %s\n", linuxCommand)
cmd := exec.Command("bash", "-c", linuxCommand)
cmdOut, err := cmd.Output()
if err != nil {
fmt.Printf("Failed to execute command\n")
writeString("Failed to execute command")
return
}
fmt.Printf("Command output: %s\n", cmdOut)
apple2string := strings.Replace(string(cmdOut), "\n", "\r", -1)
err = writeString(apple2string)
if err != nil {
fmt.Printf("Failed to send command output\n")
return
}
}
func handleGetTimeCommand() {
/* 49041 ($BF91) 49040 ($BF90)
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
DATE: | year | month | day |
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
TIME: | hour | | minute |
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
49043 ($BF93) 49042 ($BF92)
*/
now := time.Now()
year := now.Year() % 100
month := now.Month()
day := now.Day()
hour := now.Hour()
minute := now.Minute()
bf91 := (byte(year) << 1) + (byte(month) >> 3)
bf90 := ((byte(month) & 15) << 5) + byte(day)
bf93 := byte(hour)
bf92 := byte(minute)
writeByte(bf90)
writeByte(bf91)
writeByte(bf92)
writeByte(bf93)
}
func readBlock(buffer []byte) error {
for i := 0; i < 512; i++ {
err := writeByte(buffer[i])
if err != nil {
return err
}
}
return nil
}
func writeBlock(buffer []byte) error {
var err error
for i := 0; i < 512; i++ {
buffer[i], err = readByte()
if err != nil {
return err
}
}
return nil
}
func initGpio() {
out_write = gpioreg.ByName("GPIO5")
out_read = gpioreg.ByName("GPIO11")
out_commandWrite = gpioreg.ByName("GPIO9")
out_commandRead = gpioreg.ByName("GPIO10")
out_bit3 = gpioreg.ByName("GPIO22")
out_bit2 = gpioreg.ByName("GPIO27")
out_bit1 = gpioreg.ByName("GPIO17")
out_bit0 = gpioreg.ByName("GPIO4")
in_write = gpioreg.ByName("GPIO12")
in_read = gpioreg.ByName("GPIO16")
in_commandWrite = gpioreg.ByName("GPIO20")
in_commandRead = gpioreg.ByName("GPIO21")
in_bit3 = gpioreg.ByName("GPIO26")
in_bit2 = gpioreg.ByName("GPIO19")
in_bit1 = gpioreg.ByName("GPIO13")
in_bit0 = gpioreg.ByName("GPIO6")
in_write.In(gpio.PullDown, gpio.BothEdges)
in_read.In(gpio.PullDown, gpio.BothEdges)
edgeTimeout = time.Second * 5
}
func dumpBlock(buffer []byte) {
for i := 0; i < 512; i++ {
fmt.Printf("%02X ", buffer[i])
}
}
func readString() (string, error) {
var inBytes bytes.Buffer
for {
inByte,err := readByte()
if err != nil {
return "", err
}
if inByte == 0 {
break
}
inBytes.WriteByte(inByte)
}
return string(inBytes.Bytes()), nil
}
func writeString(outString string) error {
for _, character := range outString {
err := writeByte(byte(character)|128)
if err != nil {
fmt.Printf("Failed to write string\n")
return err
}
}
writeByte(0)
return nil
}
func readByte() (byte, error) {
data, err := readNibble()
data = data << byte(4)
if err != nil {
return 0, err
}
highNibble, err := readNibble()
if err != nil {
return 0, err
}
data += highNibble
//fmt.Printf("R%02X ", data)
return data, nil
}
func writeByte(data byte) error {
//fmt.Printf("W%02X ", data)
err := writeNibble(data >> 4)
if err != nil {
return err
}
err = writeNibble(data & 15)
if err != nil {
return err
}
return nil
}
func readNibble() (byte, error) {
// let the Apple II know we are ready to read
//fmt.Printf("let the Apple II know we are ready to read\n")
if debug {
fmt.Printf("let the Apple II know we are ready to read\n")
}
out_read.Out(gpio.Low)
// wait for the Apple II to write
//fmt.Printf("wait for the Apple II to write\n")
if debug {
fmt.Printf("wait for the Apple II to write\n")
}
for in_write.Read() == gpio.High {
if !in_write.WaitForEdge(edgeTimeout) {
//fmt.Printf("Timed out reading nibble -- write stuck high\n")
if debug {
fmt.Printf("Timed out reading nibble -- write stuck high\n")
}
return 0, errors.New("Timed out reading nibble -- write stuck high\n")
}
}
// get a nibble of data
//fmt.Printf("get a nibble of data\n")
if debug {
fmt.Printf("get a nibble of data\n")
}
var nibble byte
nibble = 0
bit3 := in_bit3.Read()
@ -76,7 +328,9 @@ func readNibble() (byte, error) {
//fmt.Printf("wait for the Apple II to finish writing\n")
for in_write.Read() == gpio.Low {
if !in_write.WaitForEdge(edgeTimeout) {
//fmt.Printf("Timed out reading nibble -- write stuck low\n")
if debug {
fmt.Printf("Timed out reading nibble -- write stuck low\n")
}
return 0, errors.New("Timed out reading nibble -- write stuck low")
}
}
@ -84,23 +338,16 @@ func readNibble() (byte, error) {
return nibble, nil
}
func readByte() (byte, error) {
data, err := readNibble()
data = data << byte(4)
if err != nil { return 0, err }
highNibble, err := readNibble()
if err != nil { return 0, err }
data += highNibble
//fmt.Printf("R%02X ", data)
return data, nil
}
func writeNibble(data byte) error {
// wait for the Apple II to be ready to read
//fmt.Printf("wait for the Apple II to be ready to read\n")
if debug {
fmt.Printf("wait for the Apple II to be ready to read\n")
}
for in_read.Read() == gpio.High {
if !in_read.WaitForEdge(edgeTimeout) {
//fmt.Printf("Timed out writing nibble -- read stuck high\n")
if debug {
fmt.Printf("Timed out writing nibble -- read stuck high\n")
}
return errors.New("Timed out writing nibble -- read stuck high")
}
}
@ -130,176 +377,26 @@ func writeNibble(data byte) error {
out_bit0.Out(bit0)
// let Apple II know we're writing
//fmt.Printf("let Apple II know we're writing\n")
if debug {
fmt.Printf("let Apple II know we're writing\n")
}
out_write.Out(gpio.Low)
// wait for the Apple II to finsih reading
//fmt.Printf("wait for the Apple II to finsih reading\n")
for in_read.Read() == gpio.Low {
if !in_read.WaitForEdge(edgeTimeout) {
//fmt.Printf("Timed out writing nibble -- read stuck low\n")
if debug {
fmt.Printf("Timed out writing nibble -- read stuck low\n")
}
return errors.New("Timed out writing nibble -- read stuck low")
}
}
// let the Apple II know we are done writing
//fmt.Printf("let the Apple II know we are done writing\n")
if debug {
fmt.Printf("let the Apple II know we are done writing\n")
}
out_write.Out(gpio.High)
return nil
}
func writeByte(data byte) error {
//fmt.Printf("W%02X ", data)
err := writeNibble(data >> 4)
if err != nil { return err }
err = writeNibble(data & 15)
if err != nil { return err }
return nil
}
func readBlock(buffer []byte) error {
for i := 0; i < 512; i++ {
err := writeByte(buffer[i])
if err != nil { return err }
}
return nil
}
func dumpBlock(buffer []byte) {
for i := 0; i < 512; i++ {
fmt.Printf("%02X ", buffer[i])
}
}
func writeBlock(buffer []byte) error {
var err error
for i := 0; i < 512; i++ {
buffer[i], err = readByte()
if err != nil { return err }
}
return nil
}
func main() {
host.Init()
out_write = gpioreg.ByName("GPIO5")
out_read = gpioreg.ByName("GPIO11")
out_commandWrite = gpioreg.ByName("GPIO9")
out_commandRead = gpioreg.ByName("GPIO10")
out_bit3 = gpioreg.ByName("GPIO22")
out_bit2 = gpioreg.ByName("GPIO27")
out_bit1 = gpioreg.ByName("GPIO17")
out_bit0 = gpioreg.ByName("GPIO4")
in_write = gpioreg.ByName("GPIO12")
in_read = gpioreg.ByName("GPIO16")
in_commandWrite = gpioreg.ByName("GPIO20")
in_commandRead = gpioreg.ByName("GPIO21")
in_bit3 = gpioreg.ByName("GPIO26")
in_bit2 = gpioreg.ByName("GPIO19")
in_bit1 = gpioreg.ByName("GPIO13")
in_bit0 = gpioreg.ByName("GPIO6")
in_write.In(gpio.PullDown, gpio.BothEdges)
in_read.In(gpio.PullDown, gpio.BothEdges)
edgeTimeout = time.Second * 5
fmt.Printf("Starting Apple II RPi...\n")
fileName := os.Args[1]
file, err := os.OpenFile(fileName, os.O_RDWR, 0755)
if err != nil {
fmt.Printf("ERROR: %s", err.Error())
os.Exit(1)
}
//if err := f.Close(); err != nil {
//log.Fatal(err)
//}
//for in_write.Read() == gpio.Low {
// in_write.WaitForEdge(-1)
//}
buffer := make([]byte, 512)
//file.ReadAt(buffer, int64(0) * 512)
//dumpBlock(buffer)
for {
//fmt.Printf("Check for command")
command,err := readByte();
if err != nil {
//fmt.Printf("Timed out waiting for command\n")
} else {
switch command {
case ReadBlockCommand:
blockLow,_ := readByte();
blockHigh,_ := readByte();
var block int64
block = int64(blockHigh) * 256 + int64(blockLow)
fmt.Printf("Read block %d\n", block)
file.ReadAt(buffer, int64(block) * 512)
//dumpBlock(buffer)
readBlock(buffer)
break
case WriteBlockCommand:
blockLow,_ := readByte();
blockHigh,_ := readByte();
var block int64
block = int64(blockHigh) * 256 + int64(blockLow)
fmt.Printf("Write block %d\n", block)
writeBlock(buffer)
file.WriteAt(buffer, int64(block) * 512)
file.Sync()
break
case GetTimeCommand:
/*
49041 ($BF91) 49040 ($BF90)
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
DATE: | year | month | day |
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
TIME: | hour | | minute |
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
49043 ($BF93) 49042 ($BF92)
*/
now := time.Now()
year := now.Year() % 100
month := now.Month()
day := now.Day()
hour := now.Hour()
minute := now.Minute()
bf91 := (byte(year) << 1) + (byte(month) >> 3)
bf90 := ((byte(month) & 15) << 5) + byte(day)
bf93 := byte(hour)
bf92 := byte(minute)
writeByte(bf90)
writeByte(bf91)
writeByte(bf92)
writeByte(bf93)
break
}
}
}
}