diff --git a/.gitignore b/.gitignore index cea93ba..e1b9452 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -.* -!.gitignore apple1emu.dsk +apple1emu.sym diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1aff950 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +DISK=apple1emu.dsk +ROMS=apple1.rom applesoft-lite-0.4-ram.bin ehbasic.bin 65C02.rom.bin applesoft-lite-0.4.bin + +.PHONY: clean + +$(DISK): apple1emu.asm font.bin opdefs.inc $(ROMS) + pyz80.py --exportfile=apple1emu.sym apple1emu.asm + +font.bin: font.png png2bin.pl + ./png2bin.pl font.png 6 8 + +opdefs.inc: opdefs.pl opimpl.inc apple1emu.asm + ./opdefs.pl + +clean: + rm -f $(DISK) apple1emu.sym diff --git a/font.pl b/font.pl deleted file mode 100755 index 276cbd0..0000000 --- a/font.pl +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -w -# -# Convert PNG image to raw font binary for Apple 1 emulator -# -# Makes lots of assumptions about the input image! - -use Compress::Zlib; - -# Input image and output data file -my $input = 'font.png'; -my $output = 'font.bin'; - -# Our characters are 6 pixels wide -$chrw = 6; - - -# Slurp the entire PNG image -open INPUT, "<$input" and binmode INPUT or die "$input: $!\n"; -read INPUT, $data='', -s $input; -close INPUT; - -# Find and extract the image dimensions -$data =~ /IHDR(.{8})/s; -($w,$h) = unpack "N2", $1; - -# Extract and expand the compressed image data -($data) = $data =~ /IDAT(.*).{8}IEND/s; -$data = Compress::Zlib::uncompress($data); - -# Remove the type byte from the start of each line -$w_2 = $w/2; -$data =~ s/.(.{$w_2})/$1/sg; - -@data = (); - -# Unpack the pixel nibbles -foreach (unpack "C*", $data) { - push @data, $_>>4, $_&1; -} - - -open OUTPUT, ">$output" and binmode OUTPUT or die "$output: $!\n"; - -# Process all characters -foreach $chr (0..$w/$chrw-1) -{ - # Process the image line by line - foreach $y (0..$h-1) - { - # Locate the pixel data for the current character - my $x = $chr*$chrw + $w*$y; - my $b = 0; - - # Pack the 1bpp data into a single byte - foreach (@data[$x..$x+$chrw-1]) { - $b = ($b << 1) | $_; - } - - # Left-align within the byte and output it - print OUTPUT chr($b << (8-$chrw)); - } -} - -close OUTPUT; diff --git a/make.bat b/make.bat new file mode 100755 index 0000000..612a91a --- /dev/null +++ b/make.bat @@ -0,0 +1,12 @@ +@echo off + +if "%1"=="clean" goto clean + +opimpl.pl +pyz80.py --exportfile=apple1emu.sym apple1emu.asm +goto end + +:clean +if exist apple1emu.dsk del apple1emu.dsk apple1emu.sym + +:end diff --git a/opdefs.pl b/opdefs.pl index 703194c..e2e73ef 100755 --- a/opdefs.pl +++ b/opdefs.pl @@ -1,10 +1,11 @@ #!/usr/bin/perl -w # # Calculates opcode addresses for the inline instruction decoding table -# -# Used by the Apple 1 emulator, available from: -# -# http://simonowen.com/sam/apple1emu/ + +# Allow -v option for verbose output +use Getopt::Std; +$opt_v = 0; +getopts('v'); $source = 'apple1emu.asm'; $codeend = 0xd000; @@ -75,7 +76,7 @@ MSB: # Position base so code finishes at the required point $base = $codeend - (($size + 0xff) & ~0xff); -print "Size = $size, used = $used, slack = ", $size-$used, "\n"; +print "Size = $size, used = $used, slack = ", $size-$used, "\n" unless !$opt_v; # Output sorted list of calculated positions foreach (sort { $a <=> $b } @todo) { diff --git a/png2bin.pl b/png2bin.pl new file mode 100755 index 0000000..4cb5a35 --- /dev/null +++ b/png2bin.pl @@ -0,0 +1,89 @@ +#!/usr/bin/perl -w +# +# Convert PNG image to Spectrum format sprite image data +# +# Input image should be palettised 1-bit with no transparency +# +# Simon Owen + +use Compress::Zlib; +use Getopt::Std; + +# Allow -v option for verbose output +getopts('v'); + +# Strip path from input filename, and check +$0 =~ s/.*\///; +die "Usage: $0 []\n" unless @ARGV == 2 or @ARGV == 3; + +# Input image and output data file +($file,$w,$h) = (@ARGV,$ARGV[1]); # height defaults to width if not provided +die "Input image must be in PNG format\n" unless $file =~ /.png$/i; +die "Sprite width should be 2-16 pixels\n" unless $w >= 2 && $w <= 16; +die "Sprite height should be at least 1 pixel\n" unless $h > 0; + +# Slurp the entire PNG image +open INPUT, "<$file" and binmode INPUT or die "$file: $!\n"; +read INPUT, $data='', -s $file; +close INPUT; + +# Extract and check the image dimensions +$data =~ /IHDR(.{8})/s; +($iw,$ih) = unpack "N2", $1; +die "Input image (${iw}x${ih}) must be an exact multiple of sprite size (${w}x${h})\n" if ($iw%$w) or ($ih%$h); + +# Extract and expand the compressed image data +($data) = $data =~ /IDAT(.*).{8}IEND/s; +$data = Compress::Zlib::uncompress($data); + +# Remove the type byte from the start of each line, leaving just 0+1 pixel values +if (length($data) == (($iw+1)*$ih)) { # 8bpp? + $data =~ s/.(.{$iw})/$1/sg; + @data = map { $_&1 } unpack("C*", $data); +} elsif (length($data) == (($iw/2+1)*$ih)) { # 4bpp? + my $iw_2 = $iw/2; + $data =~ s/.(.{$iw_2})/$1/sg; + foreach (unpack("C*", $data)) { + push @data, ($_>>4)&1, $_&1; + } +} else { + die "Image data format is unsupported (size = ".@data." bytes)\n"; +} + +# Calculate rows+columns and the expected size of the output data +($c,$r) = ($iw/$w,$ih/$h); +$size = int(($w+7)/8)*$h*$r*$c; +print "Input image ($file) = ${iw}x${ih}, sprite = ${w}x${h}\n" if $opt_v; + +foreach $y (0..$r-1) +{ + foreach $x (0..$c-1) + { + foreach $l (0..$h-1) # line + { + # Calculate the offset of the required bit sequence + my $o = ((($y*$h+$l)*$c) + $x) * $w; + + # Convert the individual bits to a binary string then a decimal value + my $n = unpack("N", pack("B32", substr("0"x32 . join('', @data[$o..$o+$w-1]), -32))); + + # Pack into 1 or 2 bytes, with the bits left-aligned (MSB) + $output .= pack(($w<=8)?"C":"n", $n << (8-($w & 7))); + } + } +} + +# Sanity check the output data size +die "Output data ", length($output), " is the wrong size! (should be $size)\n" unless length($output) == $size; + +# The output file is the input filename with a .bin extension instead of .png +$file =~ s/png$/bin/i; +open OUTPUT, ">$file" and binmode OUTPUT or die "$file: $!\n"; + +# Determine the size of a single sprite, and strip blank sprites from the end of the data +$ss = length($output) / ($r*$c); +$output =~ s/(\0{$ss})*$//; +print "Output data ($file) = ", length($output), " bytes = ", length($output)/$ss, " sprites\n" if $opt_v; + +print OUTPUT $output; +close OUTPUT;