Skip to content

Commit

Permalink
Added p2img (flash binary) export
Browse files Browse the repository at this point in the history
  • Loading branch information
maccasoft committed Sep 6, 2024
1 parent 18293a1 commit 1a740a6
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ void test_Spin2_debugger() throws Exception {
compileAndCompare(new File("Spin2_debugger.spin2"), new File("Spin2_debugger.binary"));
}

@Test
void test_flash_bootloader() throws Exception {
compileAndCompare(new File("flash_bootloader.spin2"), new File("flash_bootloader.binary"));
}

@Test
void test_flash_loader() throws Exception {
compileAndCompare(new File("flash_loader.spin2"), new File("flash_loader.binary"));
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
' *** SPI FLASH BOOT LOADER
'
CON spi_cs = 61
spi_ck = 60
spi_di = 59
spi_do = 58


' The ROM booter reads this code from the 8-pin SPI flash from $000000..$0003FF, into cog
' registers $000..$0FF. If the booter verifies the 'Prop' checksum, it does a 'JMP #0' to
' execute this loader code.
'
' The initial application data trailing this code in registers app_start..$0FF are moved to
' hub RAM, starting at $00000. Then, any additional application data are read from the flash
' and stored into the hub, continuing from where the initial application data left off.
'
' On entry, both spi_cs and spi_ck are low outputs and the flash is outputting bit 7 of the
' byte at address $400 on spi_do. By cycling spi_ck, any additional application data can be
' received from spi_do.
'
' Once all application data is in the hub, an application checksum is verified, after which
' cog 0 is restarted by a 'COGINIT #0,#$00000' to execute the application. If that checksum
' fails, due to some data corruption, the SPI pins will be floated and the clock stopped
' until the next reset. As well, a checksum is verified upon initial download of all data,
' before programming the flash. This all ensures that no errant application code will boot.
'
DAT org
'
'
' First, move application data in cog app_start..$0FF into hub $00000+
'
loader setq #$100-app_start-1 'move code from cog app_start..$0FF to hub $00000+
wrlong app_start,#0

sub app_longs,#$100-app_start wcz 'if app longs met or exceeded, run application
if_be coginit #0,#$00000 '(small applications verified by 'Prop' checksum)
'
'
' Read in remaining application longs
'
wrpin #%01_00101_0,#spi_ck 'set spi_ck smart pin for transitions, drives low
fltl #spi_ck 'reset smart pin
wxpin #1,#spi_ck 'set transition timebase to clk/1
drvl #spi_ck 'enable smart pin

setxfrq clk2 'set streamer rate to clk/2

wrfast #0,##$400-app_start*4 'ready to write to hub at application continuation

.block bmask x,#10 'try max streamer block size for longs ($7FF)
fle x,app_longs 'limit to number of longs left
sub app_longs,x 'update number of longs left

shl x,#5 'get number of bits
setword wmode,x,#0 'insert into streamer command
shl x,#1 'double for number of spi_ck transitions

wypin x,#spi_ck '2 start spi_ck transitions
waitx #3 '2+3 align spi_ck transitions with spi_do sampling
xinit wmode,#0 '2 start inputting spi_do bits to hub, bytes-msb-first
waitxfi '? wait for streamer to finish

tjnz app_longs,#.block 'if more longs left, read another block

wrpin #0,#spi_ck 'clear spi_ck smart pin mode
'
'
' Verify application checksum
'
rdfast #0,#0 'sum all application longs
rep #2,app_longs2
rflong x
add app_sum,x wz 'z=1 if verified

stop if_nz fltl #spi_di addpins 2 'if checksum failed, float spi_cs/spi_ck/spi_di pins
if_nz hubset #%0010 '..and stop clock until next reset

coginit #0,#$00000 'checksum verified, run application
'
'
' Data
'
clk2 long $4000_0000 'clk/2 nco value for streamer
wmode long $C081_0000 + spi_do<<17 'streamer mode, 1-pin input, bytes-msb-first, bytes to hub

zeroa '(used by programmer as long 0)
app_longs long 0 'number of longs in application (set by programmer)
zerob '(used by programmer as long 0)
app_longs2 long 0 'number of longs in application (set by programmer)
zeroc '(used by programmer as long 0)
app_sum long 0 '-sum of application longs (set by programmer)
x '(used by loader as variable)
loader_sum byte -"P",!"r",!"o",!"p" '"Prop" - sum of $100 loader longs (set by programmer)
'
'
' Application start
'
app_start 'append application bytes after this label
28 changes: 17 additions & 11 deletions modules/spin-tools/src/com/maccasoft/propeller/P1MemoryDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,13 @@ protected void buttonPressed(int buttonId) {
}

protected void doSaveBinary() {
File fileToSave = getFileToWrite();
String[] filterNames = new String[] {
"Binary Files"
};
String[] filterExtensions = new String[] {
"*.bin;*.binary"
};
File fileToSave = getFileToWrite("Save Binary File", filterNames, filterExtensions, ".binary");
try {
FileOutputStream os = new FileOutputStream(fileToSave);
os.write(object.getBinary());
Expand All @@ -816,7 +822,13 @@ protected void doSaveBinary() {
}

protected void doSaveListing() {
File fileToSave = getFileToWrite();
String[] filterNames = new String[] {
"Listing Files"
};
String[] filterExtensions = new String[] {
"*.lst;*.txt"
};
File fileToSave = getFileToWrite("Save Listing File", filterNames, filterExtensions, ".lst");
try {
PrintStream os = new PrintStream(new FileOutputStream(fileToSave));
object.generateListing(os);
Expand All @@ -826,22 +838,16 @@ protected void doSaveListing() {
}
}

protected File getFileToWrite() {
protected File getFileToWrite(String title, String[] filterNames, String[] filterExtensions, String defaultExtension) {
FileDialog dlg = new FileDialog(getShell(), SWT.SAVE);
dlg.setOverwrite(true);
dlg.setText("Save Binary File");
String[] filterNames = new String[] {
"Binary Files"
};
String[] filterExtensions = new String[] {
"*.bin;*.binary"
};
dlg.setText(title);
dlg.setFilterNames(filterNames);
dlg.setFilterExtensions(filterExtensions);

String name = tree.getName();
int i = name.lastIndexOf('.');
dlg.setFileName(name.substring(0, i) + ".binary");
dlg.setFileName(name.substring(0, i) + defaultExtension);

List<String> lru = Preferences.getInstance().getLru();

Expand Down
55 changes: 43 additions & 12 deletions modules/spin-tools/src/com/maccasoft/propeller/P2MemoryDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ public void keyTraversed(TraverseEvent e) {
@Override
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.CLIENT_ID + 1, "Save Binary", false);
createButton(parent, IDialogConstants.CLIENT_ID + 2, "Save Listing", false);
createButton(parent, IDialogConstants.CLIENT_ID + 2, "Save Flash Binary", false);
createButton(parent, IDialogConstants.CLIENT_ID + 3, "Save Listing", false);
super.createButtonsForButtonBar(parent);
}

Expand Down Expand Up @@ -816,14 +817,24 @@ protected void buttonPressed(int buttonId) {
return;
}
if (buttonId == IDialogConstants.CLIENT_ID + 2) {
doSaveFlashBinary();
return;
}
if (buttonId == IDialogConstants.CLIENT_ID + 3) {
doSaveListing();
return;
}
super.buttonPressed(buttonId);
}

protected void doSaveBinary() {
File fileToSave = getFileToWrite();
String[] filterNames = new String[] {
"Binary Files"
};
String[] filterExtensions = new String[] {
"*.bin;*.binary"
};
File fileToSave = getFileToWrite("Save Binary File", filterNames, filterExtensions, ".binary");
try {
FileOutputStream os = new FileOutputStream(fileToSave);
object.setClockSetter(Preferences.getInstance().getSpin2ClockSetter());
Expand All @@ -834,8 +845,34 @@ protected void doSaveBinary() {
}
}

protected void doSaveFlashBinary() {
String[] filterNames = new String[] {
"Flash Binary Files",
"Binary Files"
};
String[] filterExtensions = new String[] {
"*.p2img",
"*.bin;*.binary"
};
File fileToSave = getFileToWrite("Save Flash Binary File", filterNames, filterExtensions, ".p2img");
try {
FileOutputStream os = new FileOutputStream(fileToSave);
object.setClockSetter(Preferences.getInstance().getSpin2ClockSetter());
os.write(object.getEEPromBinary());
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}

protected void doSaveListing() {
File fileToSave = getFileToWrite();
String[] filterNames = new String[] {
"Listing Files"
};
String[] filterExtensions = new String[] {
"*.lst;*.txt"
};
File fileToSave = getFileToWrite("Save Listing File", filterNames, filterExtensions, ".lst");
try {
PrintStream os = new PrintStream(new FileOutputStream(fileToSave));
object.generateListing(os);
Expand All @@ -845,22 +882,16 @@ protected void doSaveListing() {
}
}

protected File getFileToWrite() {
protected File getFileToWrite(String title, String[] filterNames, String[] filterExtensions, String defaultExtension) {
FileDialog dlg = new FileDialog(getShell(), SWT.SAVE);
dlg.setOverwrite(true);
dlg.setText("Save Binary File");
String[] filterNames = new String[] {
"Binary Files"
};
String[] filterExtensions = new String[] {
"*.bin;*.binary"
};
dlg.setText(title);
dlg.setFilterNames(filterNames);
dlg.setFilterExtensions(filterExtensions);

String name = tree.getName();
int i = name.lastIndexOf('.');
dlg.setFileName(name.substring(0, i) + ".binary");
dlg.setFileName(name.substring(0, i) + defaultExtension);

List<String> lru = Preferences.getInstance().getLru();

Expand Down
43 changes: 29 additions & 14 deletions modules/spin-tools/src/com/maccasoft/propeller/SpinCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.apache.commons.cli.ParseException;

import com.maccasoft.propeller.internal.FileUtils;
import com.maccasoft.propeller.model.DirectiveNode;
Expand Down Expand Up @@ -64,8 +64,11 @@ public static void main(String[] args) {

options.addOption(Option.builder("o").desc("output file name").hasArg().argName("file").build());

options.addOption(new Option("b", false, "output binary file"));
options.addOption(new Option("c", false, "output only DAT sections"));
OptionGroup binaryOptions = new OptionGroup();
binaryOptions.addOption(new Option("b", false, "output binary file"));
binaryOptions.addOption(new Option("e", false, "output flash binary file (P2 only)"));
binaryOptions.addOption(new Option("c", false, "output only DAT sections"));
options.addOptionGroup(binaryOptions);
options.addOption(new Option("l", false, "output listing file"));
options.addOption(new Option("d", false, "enable debug (P2 only)"));

Expand Down Expand Up @@ -136,15 +139,6 @@ public static void main(String[] args) {
}
}

if (binaryFile == null) {
if (cmd.hasOption('c')) {
binaryFile = new File(fileToCompile.getParentFile(), outName + ".dat");
}
else {
binaryFile = new File(fileToCompile.getParentFile(), outName + ".binary");
}
}

if (listingFile == null) {
listingFile = new File(fileToCompile.getParentFile(), outName + ".lst");
}
Expand Down Expand Up @@ -231,16 +225,37 @@ else if ("P2".equals(node.getToken(index).getText())) {
byte[] binaryData = null;
if (cmd.hasOption('b')) {
binaryData = object.getBinary();
if (binaryFile == null) {
binaryFile = new File(fileToCompile.getParentFile(), outName + ".binary");
}
}
if (cmd.hasOption('c')) {
else if (cmd.hasOption('e')) {
binaryData = object.getEEPromBinary();
if (binaryFile == null) {
if ((compiler instanceof Spin2Compiler) || (compiler instanceof Spin2CCompiler)) {
binaryFile = new File(fileToCompile.getParentFile(), outName + ".p2img");
}
else {
binaryFile = new File(fileToCompile.getParentFile(), outName + ".eeprom");
}
}
}
else if (cmd.hasOption('c')) {
binaryData = object.getDatBinary();
if (binaryFile == null) {
binaryFile = new File(fileToCompile.getParentFile(), outName + ".dat");
}
}
if (binaryData != null) {
FileOutputStream os = new FileOutputStream(binaryFile);
os.write(binaryData);
os.close();
}

if (binaryData == null && (cmd.hasOption('r') || cmd.hasOption('f'))) {
binaryData = object.getBinary();
}

if (cmd.hasOption('l')) {
PrintStream os = new PrintStream(new FileOutputStream(listingFile));
object.generateListing(os);
Expand Down Expand Up @@ -557,7 +572,7 @@ else if (cmd == 15) { // PY: Position cursor in Y
println("Done.");
}

} catch (UnrecognizedOptionException e) {
} catch (ParseException e) {
System.out.println(e.getMessage());
} catch (CompilerException e) {
println(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,12 @@ public byte[] getBinary() throws IOException {
return os.toByteArray();
}

public byte[] getEEPromBinary() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
generateBinary(os);
return os.toByteArray();
}

public void generateDatBinary(OutputStream os) throws IOException {
for (DataObject obj : data) {
if (obj instanceof ObjectDataObject) {
Expand Down
Loading

0 comments on commit 1a740a6

Please sign in to comment.