I had a problem the other day with XSane.
It's been working awesome and then one day, the preview window wouldn't come up properly, basically a blank window.
And then I couldn't scan anything, getting an error dialog that said "Failed to start scanner: Invalid argument".
This was driving me crazy, I power cycled the hp printer/all in one 5740 but it wouldn't work at all.
So let's see if we can scan with scanimage.
scanimage -d hpaio:/net/Officejet_5740_series?ip=192.168.1.10 --format=tiff > mytest2.tiff
That worked! So why was I getting the invalid argument error? Looking carefully I saw that the area to scan was set to basically zero. The rectangle specified was basically of zero area. If you look at the top left it's set to 8.5 and 11.69 and the bottom right is 8.5 and 11.69. I must have clicked somewhere in the "blank" preview window that set these coordinates.
It'd be nice if it said "Scan Area Coordinates invalid" instead of just "invalid argument".
I see that other people have been having the same bug with the preview window:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=867667
What's interesting is that opening the preview window with CTRL+1 seems to have fixed it. Opening it with the menu Window/Show Preview was giving me the blank screen.
Anyway, I can happily scan again!
Just for fun, let's see how small a region we can actually scan without getting the "Failed to start scanner: Invalid argument" error.
The smallest I can scan is 1x1x24 (3.0B) for 3 bytes!
Saturday, December 21, 2019
Wednesday, November 20, 2019
Weirdness with VGA to HDMI adapter and i915
So I've got an older TV that I wanted to use with a laptop and do triple monitors. The laptop has got its own 1600x900 built-in screen, and on the hdmi port I've connected a DVI 1920x1200 monitor and then there's a Toshiba 40FT1U on the VGA port.
The only problem is that the Toshiba 40FT1U doesn't like anything higher than 1280x1024 or 1366x768 on the VGA port. Checking with the manual, sure enough that's the maximum on VGA-in but HDMI-in will give you the full 1080p resolution.
I got on ebay and found a cheap VGA to HDMI adapter. The only problem is that I couldn't get Ubuntu 19.04 to output a video signal that xrandr would like.
The VGA to HDMI adapter had no EDID information, and get-edid wouldn't return anything.
Firing up cvt 1920 1080 60, I would make an xrandr newmode of 1920x1080.
Sadly, that didn't work at all giving a "Configure crtc 1 failed" message.
Looking at my xorg log it says just Invalid argument:
What's strange is that I can do a resolution of 1912x1080:
So 1912x1080x60 works no problem, which is really strange. The only problem is that my VGA to HDMI adapter scrunches the screen horizontally, which is usable but it offends me terribly. Not having 1 to 1 pixels grated on me.
I've got another television a 50 inch emerson with a VGA input, and weirdly, plugging the VGA into it allows me to set a 1920x1080x60 resolution. Oddly, it has no EDID information either but the 1920x1080 resolution will work.
So I thought, let's see if we can get a working edid from another monitor and use that.
On another system with a sceptre monitor that was 1920x1080 I ran "sudo get-edid > sceptre_edid.bin".
Then I made a /usr/firmware/edid directory with "sudo mkdir /usr/firmware/edid" then "sudo cp sceptre_edid.bin /usr/firmware/edid/"/
Locating the file /etc/default/grub and running "sudo nano /etc/default/grub"
then "sudo update-grub"
and now it comes up just fine with 1920x1080 on the VGA-1 port.
So what is actually not working? Let's take a closer look at the EDID file with parse-edid.
That modeline of "Mode 0" is 1920x1080 but the numbers are different from what cvt gives:
Comparing the two modelines, the numbers vary slightly and the hsync is opposite polarity.
Let's compare it to a reduced blanking modeline from cvt, now you'll notice that the vsync is opposite.
$ cvt 1920 1080 60 -r
# 1920x1080 59.93 Hz (CVT 2.07M9-R) hsync: 66.59 kHz; pclk: 138.50 MHz
Modeline "1920x1080R" 138.50 1920 1968 2000 2080 1080 1083 1088 1111 +hsync -vsync
Modeline "Mode 0" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync
So I tried rebooting ubuntu *without* the drm.edid_firmware=VGA-1:edid/sceptre_edid.bin and it went right back to hating my cvt 1920 1080 60 modeline.
But let's try the modeline from the sceptre edid "Mode 0".
$ xrandr --newmode "Mode 0" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync
$ xrandr --addmode VGA-1 "Mode 0"
$ xrandr --output VGA-1 --mode "Mode 0"
Hah! It likes that modeline!
It also seems to like the reduced blanking version.
$ cvt -r 1920 1080 60
# 1920x1080 59.93 Hz (CVT 2.07M9-R) hsync: 66.59 kHz; pclk: 138.50 MHz
Modeline "1920x1080R" 138.50 1920 1968 2000 2080 1080 1083 1088 1111 +hsync -vsync
$ xrandr --newmode "1920x1080R" 138.50 1920 1968 2000 2080 1080 1083 1088 1111 +hsync -vsync
$ xrandr --addmode VGA-1 "1920x1080R"
$ xrandr --output VGA-1 --mode "1920x1080R"
I also tried gtf and that didn't work. xrandr: Configure crtc 1 failed
Strangely, using drm.edid_firmware=VGA-1:edid/1920x1080.bin would work on the VGA to HDMI but for some reason I'd lose the other monitor.
(This would use a "built-in" 1920x1080 edid file)
The actual 1920x1080 timings can vary, here's a couple of monitors that have 1125 as the last number of the modeline.
From https://cdn.kramerav.com/web/downloads/white-papers/analog_edid_whitepaper_6.pdf:
"Knowing that the standardization problem exists mostly in widescreen resolutions, let us look at an example using 1920x1080.
These mode lines came from the EDIDs of the computer graphics video inputs of different 1080p monitors:"
"You can clearly see that while all these monitors claim to be 1920x1080 monitors, they each support a different version of 1920x1080. It is also clear that describing active pixels alone is not specific enough to define a resolution. Display manufacturers have taken to producing non-standard displays, because the specific timings are completely described in the EDID of the monitors they build. When a computer is connected directly to any of these monitors, the mode line is read by the PC and automatically the PC modifies its output to comply properly with that display."
Now with the edid file I can get my VGA to HDMI adapter to work with full 1920x1080 resolution automatically or using the "Mode 0" modeline from the edid file I can get xrandr to work. The VGA to HDMI output really looks good on the tv.
The only problem is that the Toshiba 40FT1U doesn't like anything higher than 1280x1024 or 1366x768 on the VGA port. Checking with the manual, sure enough that's the maximum on VGA-in but HDMI-in will give you the full 1080p resolution.
I got on ebay and found a cheap VGA to HDMI adapter. The only problem is that I couldn't get Ubuntu 19.04 to output a video signal that xrandr would like.
The VGA to HDMI adapter had no EDID information, and get-edid wouldn't return anything.
Firing up cvt 1920 1080 60, I would make an xrandr newmode of 1920x1080.
$ cvt 1920 1080 60
# 1920x1080 59.96 Hz (CVT 2.07M9) hsync: 67.16 kHz; pclk: 173.00 MHz
Modeline "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
$ xrandr --newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
$ xrandr --addmode VGA-1 "1920x1080_60.00"
$ xrandr --output VGA-1 --mode "1920x1080_60.00"
xrandr: Configure crtc 1 failed
Sadly, that didn't work at all giving a "Configure crtc 1 failed" message.
Looking at my xorg log it says just Invalid argument:
$ less ~/.local/share/xorg/Xorg.0.log
[ 405.766] (II) modeset(0): Allocate new frame buffer 5440x1200 stride
[ 1196.778] (EE) modeset(0): failed to set mode: Invalid argument
What's strange is that I can do a resolution of 1912x1080:
$ cvt 1912 1080 60
# 1912x1080 59.91 Hz (CVT) hsync: 67.10 kHz; pclk: 171.25 MHz
Modeline "1912x1080_60.00" 171.25 1912 2032 2232 2552 1080 1083 1093 1120 -hsync +vsync
$ xrandr --newmode "1912x1080_60.00" 171.25 1912 2032 2232 2552 1080 1083 1093 1120 -hsync +vsync
$ xrandr --addmode VGA-1 "1912x1080_60.00"
$ xrandr --output VGA-1 --mode "1912x1080_60.00"
So 1912x1080x60 works no problem, which is really strange. The only problem is that my VGA to HDMI adapter scrunches the screen horizontally, which is usable but it offends me terribly. Not having 1 to 1 pixels grated on me.
I've got another television a 50 inch emerson with a VGA input, and weirdly, plugging the VGA into it allows me to set a 1920x1080x60 resolution. Oddly, it has no EDID information either but the 1920x1080 resolution will work.
So I thought, let's see if we can get a working edid from another monitor and use that.
On another system with a sceptre monitor that was 1920x1080 I ran "sudo get-edid > sceptre_edid.bin".
Then I made a /usr/firmware/edid directory with "sudo mkdir /usr/firmware/edid" then "sudo cp sceptre_edid.bin /usr/firmware/edid/"/
Locating the file /etc/default/grub and running "sudo nano /etc/default/grub"
and making these changes:
GRUB_TIMEOUT=10
GRUB_TIMEOUT_STYLE=menu
GRUB_CMDLINE_LINUX=" drm.edid_firmware=VGA-1:edid/sceptre_edid.bin"
then "sudo update-grub"
and now it comes up just fine with 1920x1080 on the VGA-1 port.
So what is actually not working? Let's take a closer look at the EDID file with parse-edid.
$ cat sceptre_edid.bin | parse-edid
Checksum Correct
Section "Monitor"
Identifier "E275W-1920"
ModelName "E275W-1920"
VendorName "SPT"
# Monitor Manufactured week 6 of 2015
# EDID version 1.3
# Analog Display
Option "SyncOnGreen" "true"
DisplaySize 600 340
Gamma 2.20
Option "DPMS" "true"
Horizsync 30-95
VertRefresh 56-75
# Maximum pixel clock is 180MHz
#Not giving standard mode: 1280x800, 60Hz
#Not giving standard mode: 1280x960, 60Hz
#Not giving standard mode: 1280x1024, 60Hz
#Not giving standard mode: 1440x900, 60Hz
#Not giving standard mode: 1600x1200, 60Hz
#Not giving standard mode: 1680x1050, 60Hz
Modeline "Mode 0" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync
Modeline "Mode 1" 118.97 1600 1712 1864 2112 900 901 904 932 -hsync +vsync
EndSection
That modeline of "Mode 0" is 1920x1080 but the numbers are different from what cvt gives:
Comparing the two modelines, the numbers vary slightly and the hsync is opposite polarity.
Modeline "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
Modeline "Mode 0" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync
Let's compare it to a reduced blanking modeline from cvt, now you'll notice that the vsync is opposite.
$ cvt 1920 1080 60 -r
# 1920x1080 59.93 Hz (CVT 2.07M9-R) hsync: 66.59 kHz; pclk: 138.50 MHz
Modeline "1920x1080R" 138.50 1920 1968 2000 2080 1080 1083 1088 1111 +hsync -vsync
Modeline "Mode 0" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync
So I tried rebooting ubuntu *without* the drm.edid_firmware=VGA-1:edid/sceptre_edid.bin and it went right back to hating my cvt 1920 1080 60 modeline.
But let's try the modeline from the sceptre edid "Mode 0".
$ xrandr --newmode "Mode 0" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync
$ xrandr --addmode VGA-1 "Mode 0"
$ xrandr --output VGA-1 --mode "Mode 0"
Hah! It likes that modeline!
It also seems to like the reduced blanking version.
$ cvt -r 1920 1080 60
# 1920x1080 59.93 Hz (CVT 2.07M9-R) hsync: 66.59 kHz; pclk: 138.50 MHz
Modeline "1920x1080R" 138.50 1920 1968 2000 2080 1080 1083 1088 1111 +hsync -vsync
$ xrandr --newmode "1920x1080R" 138.50 1920 1968 2000 2080 1080 1083 1088 1111 +hsync -vsync
$ xrandr --addmode VGA-1 "1920x1080R"
$ xrandr --output VGA-1 --mode "1920x1080R"
I also tried gtf and that didn't work. xrandr: Configure crtc 1 failed
Strangely, using drm.edid_firmware=VGA-1:edid/1920x1080.bin would work on the VGA to HDMI but for some reason I'd lose the other monitor.
(This would use a "built-in" 1920x1080 edid file)
The actual 1920x1080 timings can vary, here's a couple of monitors that have 1125 as the last number of the modeline.
From https://cdn.kramerav.com/web/downloads/white-papers/analog_edid_whitepaper_6.pdf:
"Knowing that the standardization problem exists mostly in widescreen resolutions, let us look at an example using 1920x1080.
These mode lines came from the EDIDs of the computer graphics video inputs of different 1080p monitors:"
Monitor 1 – LG LCD
• Detailed timing #1....... 1920x1080p at 60Hz (16:9)
• Mode line............... “1920x1080” 148.500 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync
Monitor 2 – Westinghouse LCD
• Native/preferred timing.... 1920x1080p at 60Hz (16:9)
• Mode line............... “1920x1080” 138.500 1920 1968 2000 2080 1080 1082 1087 1111 +hsync -vsync
Monitor 3 – Samsung LCD
• Native/preferred timing.. 1920x1080p at 60Hz (16:9)
• Mode line............... “1920x1080” 138.500 1920 1968 2000 2080 1080 1083 1088 1111 +hsync -vsync
Monitor 4 – Panasonic Plasma
• Detailed timing #1....... 1920x1080p at 60Hz
• Mode line............... “1920x1080” 148.500 1920 2008 2052 2200 1080 1084 1089 1125 -hsync –vsync
Monitor 5 – Vizio LCD
• Native/preferred timing.. 1920x1080p at 60Hz
• Mode line............... “1920x1080” 136.500 1920 1952 1984 2048 1080 1081 1084 1111 +hsync +vsync
"You can clearly see that while all these monitors claim to be 1920x1080 monitors, they each support a different version of 1920x1080. It is also clear that describing active pixels alone is not specific enough to define a resolution. Display manufacturers have taken to producing non-standard displays, because the specific timings are completely described in the EDID of the monitors they build. When a computer is connected directly to any of these monitors, the mode line is read by the PC and automatically the PC modifies its output to comply properly with that display."
Now with the edid file I can get my VGA to HDMI adapter to work with full 1920x1080 resolution automatically or using the "Mode 0" modeline from the edid file I can get xrandr to work. The VGA to HDMI output really looks good on the tv.
Friday, July 19, 2019
Non blocking reads in lua
So I wanted to try reading some midi data from my keyboard with lua and ubuntu. I installed lua 5.3 and lua posix with "sudo apt install lua5.3 lua-posix"
Then I plugged in my M-Audio Keyrig 49 to the usb and tested it with "aseqdump -l" to list the midi devices then "aseqdump -p 24:0" since it came up on port 24:0.
Ok, so now for the lua (something quick and hacky to test it):
The keyrig will generate 0x90 key on and always 3 bytes for each midi message (0x90 status, then pitch, the velocity) so that makes it really easy.
Then I plugged in my M-Audio Keyrig 49 to the usb and tested it with "aseqdump -l" to list the midi devices then "aseqdump -p 24:0" since it came up on port 24:0.
Ok, so now for the lua (something quick and hacky to test it):
The keyrig will generate 0x90 key on and always 3 bytes for each midi message (0x90 status, then pitch, the velocity) so that makes it really easy.
and some sample output:
................................................
90
3b
39
KEY=59 VELOCITY=57
.......................*.........................
9
90
3c
36
KEY=60 VELOCITY=54
.......................**........................
6
90
3e
23
KEY=62 VELOCITY=35
.......................**.*......................
Saturday, May 4, 2019
MTU 80 Column 3d hat
I remember this program that I typed in from a magazine years ago that would draw a neat 3d function. So let's see if we can find it:
https://j-b.livejournal.com/268176.html
Atari 8-bit "Archimedes Spiral" demo - FOUND!
I searched google for:
mtu commodore pet graphics "high-resolution"
which led me to an ebay ad and if you look closely it says "May 1981" so let's see what we can find for ads for MTU in may 1981.
Micro, the 6502 magazine, may 1981 page
http://archive.6502.org/publications/micro/micro_36_may_1981.pdf
I found the original source for the ebay ad picture:
https://archive.org/details/creativecomputing-1981-05/page/n67
And another page that mentions the MTU ad and rewriting it in 68000
http://www.easy68k.com/paulrsm/dg/dg07.htm
It was originally for the PET with a MTU graphics board, but it wasn't hard to convert to Apple II Applesoft Basic, but I kept getting illegal quantity errors on the hplots being outside of the range 0-279 for x and 0-191 for y so there's code to keep them within range.
You can paste the program into mame's lua console and then unthrottle with F10 and set the frameskip to skip 10/10 it to run it really fast. If you shrink the mame window it will go even faster. I think I can get it to 1200% on my system so it only takes about 8 minutes.
https://j-b.livejournal.com/268176.html
Atari 8-bit "Archimedes Spiral" demo - FOUND!
I searched google for:
mtu commodore pet graphics "high-resolution"
which led me to an ebay ad and if you look closely it says "May 1981" so let's see what we can find for ads for MTU in may 1981.
Micro, the 6502 magazine, may 1981 page
http://archive.6502.org/publications/micro/micro_36_may_1981.pdf
I found the original source for the ebay ad picture:
https://archive.org/details/creativecomputing-1981-05/page/n67
And another page that mentions the MTU ad and rewriting it in 68000
http://www.easy68k.com/paulrsm/dg/dg07.htm
It was originally for the PET with a MTU graphics board, but it wasn't hard to convert to Apple II Applesoft Basic, but I kept getting illegal quantity errors on the hplots being outside of the range 0-279 for x and 0-191 for y so there's code to keep them within range.
You can paste the program into mame's lua console and then unthrottle with F10 and set the frameskip to skip 10/10 it to run it really fast. If you shrink the mame window it will go even faster. I think I can get it to 1200% on my system so it only takes about 8 minutes.
emu.keypost([[
NEW
10 HGR2 : HCOLOR=3
20 P=160 : Q=100
30 XP=120:XR=1.5*3.1415927
40 YP=56:YR=1:ZP=64
50 XF=XR/XP:YF=YP/YR:ZF=XR/ZP
60 FOR ZI=-Q TO Q-1
70 IF ZI<-ZP OR ZI>ZP GOTO 150
80 ZT=ZI*XP/ZP:ZZ=ZI
90 XL=INT(.5+SQR(XP*XP-ZT*ZT))
100 FOR XI=-XL TO XL
110 XT=SQR(XI*XI+ZT*ZT)*XF:XX=XI
120 YY=(SIN(XT)+.4*SIN(3*XT))*YF
130 GOSUB 170
140 NEXT XI
150 NEXT ZI
160 STOP
170 X1=XX+ZZ+P
180 Y1=YY-ZZ+Q
181 IF Y1<1 THEN Y1=1 : REM MUST BE 1 OR ERROR IN 210
182 IF Y1>191 THEN Y1=191
183 IF X1<0 THEN X1=0
184 IF X1>279 THEN X1=279
190 HCOLOR=3:HPLOT X1,191-Y1
210 HCOLOR=0:HPLOT X1,191-(Y1-1) TO X1,191-0
220 RETURN
RUN
]])
I also like this applesoft program to plot the gaussian distribution in 3d on codegolf:
https://codegolf.stackexchange.com/questions/123039/plot-the-gaussian-distribution-in-3d/123079
Wednesday, March 27, 2019
Some Ubuntu resume weirdness, lose mouse, sound
For some reason, I keep losing my mouse on resume. I can unplug it from the top of my keyboard and then plug it in and it will come back. I've also noticed that it will come back properly if I keep moving the mouse during the resume process, until the screen comes back and I can see the mouse moving. What's weird when it happens is that the scroll wheel works, but I can't move the mouse at all until doing an unplug/replug cycle.
Also sometimes I will lose my sound which is pretty irritating.
https://superuser.com/questions/845645/pulseaudio-how-to-rescan-audio-devices
https://askubuntu.com/questions/517578/no-sound-after-suspend-standby
This command will re-detect the sound devices:
pacmd unload-module module-udev-detect && pacmd load-module module-udev-detect
Also you can ask alsa to force reload itself, just doing sudo alsa force-reload didn't bring my sound back, I also had to do the pacmd unload-module module-udev-detect && pacmd load-module module-udev-detect.
sudo alsa force-reload
cat /proc/asound/cards
pacmd list-sinks
pacmd unload-module module-udev-detect && pacmd load-module module-udev-detect
pacmd list-sinks
Tuesday, January 29, 2019
Stellar 7 text font at 0x7900
Monday, January 28, 2019
More COS routine multiply analysis.
Binary math really melts my brain. I'm not really designed to function in binary so I've been trying to figure out how the multiply routine ends up with a costable value * multiplicand *2.
I think it's useful to build a model to see exactly what's happening with the bits.
And if I run this in mame's lua console I can better see where all those bits are going:
I think it's useful to build a model to see exactly what's happening with the bits.
And if I run this in mame's lua console I can better see where all those bits are going:
7 bits of multiplier mem00=7f mem01=ff LDX $01=ff DEX STX $01=fe LDA $00=7f LSR A=3f STA $02=3f LDA #$00 a=00 BEFORE ADC $01=fe a=00 00000000 ADD ADC (c=1+$01)=ff 11111111 AFTER ADC $01=fe a=ff 11111111 c=0 BEFORE ROL: 0_11111111_00111111 ROL8 BEFORE= ff carry= 0 11111111 ROL8 AFTER = 7f carry= 1 01111111 ROL8 BEFORE= 3f carry= 1 00111111 ROL8 AFTER = 9f carry= 1 10011111 AFTER ROL: 1_01111111_10011111 1 7f 01111111 9f 10011111 BEFORE ADC $01=fe a=7f 01111111 ADD ADC (c=1+$01)=ff 11111111 AFTER ADC $01=fe a=7e 01111110 c=1 BEFORE ROL: 1_01111110_10011111 ROL8 BEFORE= 7e carry= 1 01111110 ROL8 AFTER = bf carry= 0 10111111 ROL8 BEFORE= 9f carry= 0 10011111 ROL8 AFTER = 4f carry= 1 01001111 AFTER ROL: 1_10111111_01001111 1 bf 10111111 4f 01001111 BEFORE ADC $01=fe a=bf 10111111 ADD ADC (c=1+$01)=ff 11111111 AFTER ADC $01=fe a=be 10111110 c=1 BEFORE ROL: 1_10111110_01001111 ROL8 BEFORE= be carry= 1 10111110 ROL8 AFTER = df carry= 0 11011111 ROL8 BEFORE= 4f carry= 0 01001111 ROL8 AFTER = 27 carry= 1 00100111 AFTER ROL: 1_11011111_00100111 1 df 11011111 27 00100111 BEFORE ADC $01=fe a=df 11011111 ADD ADC (c=1+$01)=ff 11111111 AFTER ADC $01=fe a=de 11011110 c=1 BEFORE ROL: 1_11011110_00100111 ROL8 BEFORE= de carry= 1 11011110 ROL8 AFTER = ef carry= 0 11101111 ROL8 BEFORE= 27 carry= 0 00100111 ROL8 AFTER = 13 carry= 1 00010011 AFTER ROL: 1_11101111_00010011 1 ef 11101111 13 00010011 BEFORE ADC $01=fe a=ef 11101111 ADD ADC (c=1+$01)=ff 11111111 AFTER ADC $01=fe a=ee 11101110 c=1 BEFORE ROL: 1_11101110_00010011 ROL8 BEFORE= ee carry= 1 11101110 ROL8 AFTER = f7 carry= 0 11110111 ROL8 BEFORE= 13 carry= 0 00010011 ROL8 AFTER = 09 carry= 1 00001001 AFTER ROL: 1_11110111_00001001 1 f7 11110111 09 00001001 BEFORE ADC $01=fe a=f7 11110111 ADD ADC (c=1+$01)=ff 11111111 AFTER ADC $01=fe a=f6 11110110 c=1 BEFORE ROL: 1_11110110_00001001 ROL8 BEFORE= f6 carry= 1 11110110 ROL8 AFTER = fb carry= 0 11111011 ROL8 BEFORE= 09 carry= 0 00001001 ROL8 AFTER = 04 carry= 1 00000100 AFTER ROL: 1_11111011_00000100 1 fb 11111011 04 00000100 BEFORE ADC $01=fe a=fb 11111011 ADD ADC (c=1+$01)=ff 11111111 AFTER ADC $01=fe a=fa 11111010 c=1 BEFORE ROL: 1_11111010_00000100 ROL8 BEFORE= fa carry= 1 11111010 ROL8 AFTER = fd carry= 0 11111101 ROL8 BEFORE= 04 carry= 0 00000100 ROL8 AFTER = 02 carry= 0 00000010 AFTER ROL: 0_11111101_00000010 0 fd 11111101 02 00000010 [MAME]> [MAME]> print(hex(0xff * 0x7f * 2)) fd02 [MAME]>
Friday, January 25, 2019
Cos and Sin multiplication routine at 0xD00.
So let's disassemble Stellar 7's cos and sin multiplication routine and write it to a file with the dasm command.
dasm d00_multiplication_dasm.txt,d00,f6
This will dissassemble from d00-df5.
As input, it takes the number to be multiplied in $00, the angle in A.
As output, the COS(A) * $00 goes in $22-23 and the SIN A goes in $24-25. The high byte of the output will always be zero. The multiplication generates 16 bits, we're only interested in the high byte, the remainder goes in $02 but it is just ignored.
Another thing to note is that the cos table values are 7 bits with the high bit used as a sign bit.
The cos table represent fractions from 0 to 80.
0x0 represents 0.0 and 0x80 represents 1.0.
But we only have 7 bits, from 0 to 0x7F, we can't actually get 1.0. That's why we've got the special case handling of the angles at 0,90,180 and 270 degrees.
0x7f divided by 128 gets pretty close to 1.0, about 99.2%.
print (0x7f/0x80)
0.9921875
The multiplication routine multiplies by the 7 bits of the lookup table value and then multiplies that by 2.
Therefore our multiplication routine can only get up to multiplying by 0x7f * 2 = 0xfe or 254.
===============================
Example: multiplying by 0x7f or (.992)
So for example, let's take a number, say 0x19 and multiply it by 0x7F and then multiply it by 2. We get
print (string.format("%x",0x7f*0x19*2))
18ce
We take the result of 0x18CE, throw away the low byte of the result 0xCE and we get 0x18 which is 99% of 0x19.
Example: multiplying by 0x40 or (0.5)
So for another example, let's take our same number, say 0x19 and multiply it by 0x40 and then multiply it by 2. We get
print (string.format("%x",0x40*0x19*2))
c80
We take the result of 0xC80, throw away the low byte of the result 0x80 and we get 0xC which is 0.5 * 0x19 or 0xC. 0x19=25 0xC=12.
Basically what we're doing is multiplying by our cos value fraction (0 to 255) and then shifting that result by 8 bits (dividing by 256 by throwing away the low byte).
result = (multiplicand * ((cosvalue AND 0x7f) * 2) / 256
The sign bit is handled specially, we just negate the result by EOR #$FF and ADC #$00 (with the sign bit set, effectively adds by 1).
==================================
Special cases:
First thing we do is to look and see if the number is zero. If so, then we can just put #$00 in $22-23 and $24-25 and rts.
At 0d0d, there's a TAY make a copy of the angle and store it in Y.
We and it with #$3f to check to see if it's any of the special angle cases, 0,0x40,0x80,0xc0 or 0,90,128,192 degrees. If A is zero after anding with #$3f, then we know it's a special case and we jmp to $0db3.
The special cases are pretty straightforward, if the angle is 0, cos 0 = 1, sin 0 = 0. Therefore at $0db6 we copy $00 to $22, put #$00 in $23,$24 and $25.
If the angle is 90, cos 90=0, sin 90=1.
If the angle is 180, cos 180=-1, sin 180=0. So return negative $00 in $22-23, #$00 in $24-25.
If the angle is 270, cos 90=0, sin 90=-1, at $0de6 we put #$00 in $22-23 and we do a subtraction of $00 from #$00 and put that in $24 (ldx #$00,txa,sec,sbc $00,sta $25) and put #$FF in $25 (ldx #$00,dex and stx $25).
0D00: A6 00 ldx $00 0D02: D0 09 bne $0d0d 0D04: 86 22 stx $22 0D06: 86 23 stx $23 0D08: 86 24 stx $24 0D0A: 86 25 stx $25 0D0C: 60 rts 0D0D: A8 tay copy the angle into y 0D0E: 29 3F and #$3f 0D10: D0 03 bne $0d15 0D12: 4C B3 0D jmp $0db3 jmp to 0db3, one of our special cases 00,40,80,c0. 0D15: B9 00 0F lda $0f00, y get our lookup table value 0D18: CA dex decrement x (because when we do the adds, the carry bit will be set) 0D19: 86 01 stx $01 store x in $01 (multiplicand minus 1 goes in $01) 0D1B: 4A lsr a shift a right 0D1C: 85 02 sta $02 store a in $02 (will shift bits in and out of $02 with ror, when done $02=low byte of result) 0D1E: A9 00 lda #$00 0D20: 90 02 bcc $0d24 0D22: 65 01 adc $01 0D24: 6A ror a 0D25: 66 02 ror $02 0D27: 90 02 bcc $0d2b 0D29: 65 01 adc $01 0D2B: 6A ror a 0D2C: 66 02 ror $02 0D2E: 90 02 bcc $0d32 0D30: 65 01 adc $01 0D32: 6A ror a 0D33: 66 02 ror $02 0D35: 90 02 bcc $0d39 0D37: 65 01 adc $01 0D39: 6A ror a 0D3A: 66 02 ror $02 0D3C: 90 02 bcc $0d40 0D3E: 65 01 adc $01 0D40: 6A ror a 0D41: 66 02 ror $02 0D43: 90 02 bcc $0d47 0D45: 65 01 adc $01 0D47: 6A ror a 0D48: 66 02 ror $02 0D4A: 90 02 bcc $0d4e 0D4C: 65 01 adc $01 0D4E: 6A ror a 0D4F: 66 02 ror $02 0D51: A2 00 ldx #$00 0D53: 90 07 bcc $0d5c no sign bit, so let's branch to d5c 0D55: 49 FF eor #$ff sign bit is set, so negate our result A by EOR #$FF, and ADC #$00 (carry is set) 0D57: 69 00 adc #$00 0D59: F0 01 beq $0d5c need this branch here, because if A was 0, we don't want -0 to come back as FF00 (-256). 0D5B: CA dex decrement x so x will be #$FF 0D5C: 85 22 sta $22 0D5E: 86 23 stx $23 0D60: A6 00 ldx $00 0D62: 98 tya Multiply by SIN value, first get the angle from the Y register 0D63: 18 clc 0D64: 69 C0 adc #$c0 add #$c0 (add 192) since sin A is cos(A-0x40)=(A+0x100-0x40), addition wraps around 0-255 0D66: A8 tay put our new angle (+192) back into Y 0D67: B9 00 0F lda $0f00, y get the value from the cos table 0D6A: CA dex 0D6B: 86 01 stx $01 0D6D: 4A lsr a 0D6E: 85 02 sta $02 0D70: A9 00 lda #$00 0D72: 90 02 bcc $0d76 0D74: 65 01 adc $01 0D76: 6A ror a 0D77: 66 02 ror $02 0D79: 90 02 bcc $0d7d 0D7B: 65 01 adc $01 0D7D: 6A ror a 0D7E: 66 02 ror $02 0D80: 90 02 bcc $0d84 0D82: 65 01 adc $01 0D84: 6A ror a 0D85: 66 02 ror $02 0D87: 90 02 bcc $0d8b 0D89: 65 01 adc $01 0D8B: 6A ror a 0D8C: 66 02 ror $02 0D8E: 90 02 bcc $0d92 0D90: 65 01 adc $01 0D92: 6A ror a 0D93: 66 02 ror $02 0D95: 90 02 bcc $0d99 0D97: 65 01 adc $01 0D99: 6A ror a 0D9A: 66 02 ror $02 0D9C: 90 02 bcc $0da0 0D9E: 65 01 adc $01 0DA0: 6A ror a 0DA1: 66 02 ror $02 0DA3: A2 00 ldx #$00 0DA5: 90 07 bcc $0dae 0DA7: 49 FF eor #$ff 0DA9: 69 00 adc #$00 0DAB: F0 01 beq $0dae 0DAD: CA dex 0DAE: 85 24 sta $24 0DB0: 86 25 stx $25 0DB2: 60 rts 0DB3: 98 tya we copied the angle to the Y register before, so copy angle back to A 0DB4: D0 0D bne $0dc3 0DB6: A2 00 ldx #$00 angle = 0 or #$00, cos = 1, sin = 0 0DB8: 86 24 stx $24 0DBA: 86 25 stx $25 0DBC: A5 00 lda $00 0DBE: 85 22 sta $22 0DC0: 86 23 stx $23 0DC2: 60 rts 0DC3: 30 0D bmi $0dd2 0DC5: A2 00 ldx #$00 angle = 90 or #$40, cos = 0, sin = 1 0DC7: 86 22 stx $22 0DC9: 86 23 stx $23 0DCB: A5 00 lda $00 0DCD: 85 24 sta $24 0DCF: 86 25 stx $25 0DD1: 60 rts 0DD2: 29 40 and #$40 0DD4: D0 10 bne $0de6 0DD6: A2 00 ldx #$00 angle = 180 or #$80, cos = -1, sin = 0 0DD8: 86 24 stx $24 0DDA: 86 25 stx $25 0DDC: 38 sec 0DDD: 8A txa 0DDE: E5 00 sbc $00 0DE0: 85 22 sta $22 0DE2: CA dex 0DE3: 86 23 stx $23 0DE5: 60 rts 0DE6: A2 00 ldx #$00 angle = 270 or #$C0, cos = 0, sin = -1 0DE8: 86 22 stx $22 0DEA: 86 23 stx $23 0DEC: 38 sec 0DED: 8A txa 0DEE: E5 00 sbc $00 0DF0: 85 24 sta $24 0DF2: CA dex 0DF3: 86 25 stx $25 0DF5: 60 rts
Thursday, January 24, 2019
Comparing the cosine table to math.cos
Let's see how closely Stellar 7's cosine table compares to math.cos().
There's some interesting patterns in the difference between the cosine table and math.cos. It's never more than 1/128 or about +/- 1% difference. The horizontal lines are the range -(1/128) to +(1/128).
I wonder how this compares to Ulugh Beg's cos table.
There's some interesting patterns in the difference between the cosine table and math.cos. It's never more than 1/128 or about +/- 1% difference. The horizontal lines are the range -(1/128) to +(1/128).
I wonder how this compares to Ulugh Beg's cos table.
Wednesday, January 23, 2019
Finding Stellar 7's cos table
I really love the mame debugger. I've got a new project: to figure out how Stellar 7's code works. It's such a genius game, I want to know how it was done.
So how does it do the math?
It stores the cos table in 0xF00 to 0xFFF, where the angle goes from 0 to 255. The high bit of the entry is the sign bit and the cos value is the low 7 bits. A value of 127 represents a value of 1.0, and a value of 0 represents 0.0. 128 represents the value of -0. 255 represents a value of -1.0.
In the next installment I'll show how it does the multiplication using the table.
To display the cos table, let's do a little bit of lua to render it to the apple's screen memory. If you've got the debugger open, just single step to get the screen to update.
So how does it do the math?
It stores the cos table in 0xF00 to 0xFFF, where the angle goes from 0 to 255. The high bit of the entry is the sign bit and the cos value is the low 7 bits. A value of 127 represents a value of 1.0, and a value of 0 represents 0.0. 128 represents the value of -0. 255 represents a value of -1.0.
In the next installment I'll show how it does the multiplication using the table.
To display the cos table, let's do a little bit of lua to render it to the apple's screen memory. If you've got the debugger open, just single step to get the screen to update.
Saturday, January 12, 2019
Stellar 7 cheats
Apple 2 version
81fc = shield
b@81fc=92 max shield (don't go above 92 or will overwrite the boundary)
81fe = fuel
b@81fe = 92 max fuel (don't go above 92 or will overwrite the boundary)
Playing Stellar7 with mame at double speed:
./mame64 apple2p stellar7 -speed 2.0 -frameskip 6
Thursday, January 10, 2019
Sirius Joyport and mame's apple2 driver
So I was reading up on the Sirius Joyport which was a box to convert Atari Joysticks to the Apple 2 Gameport and thought that it wouldn't be hard to add to mame's apple2 driver. All it really does is put an atari joystick on Pushbuttons 0,1 and 2 and selecting the button to read with annunciator #1.
https://www.atarimagazines.com/cva/v1n1/joysticks.php
or if you want the original source of the article:
https://archive.org/details/Video_Arcade_Games_Vol_1_No_1_1983-09_Creative_Computing_US/page/n101
It's a bit of a hack, but it's more of a proof of concept than anything else. You can switch the gameport from normal to sirius joyport on the fly which is useful.
Boulderdash with the Startup Screen where you can select the Joyport by pressing J.
Stellar 7 controls screen, you can select the Joyport with CTRL+A.
The games that I've found to work with the Sirius Joyport are:
Berzap!
Borg
Wavy Navy
Seadragon
Boulder Dash 1, Boulder Dash 2
Dino Eggs
Bouncing Kamungas
Lunar Leeper
Roundabout
Pest Patrol
Jawbreaker II
Vindicators (CTRL+M)
Miner 2049er, Miner II
Stellar 7
Outpost
Fly Wars
Lemmings
Plasmania
Stellar 7 really gets fast and furious with ramping the speed up to 1.5 or 2.0. What a superb game.
./mame64 apple2p stellar7 -speed 2.0
I can only finish the game with save states! Shift+F7 and F7 are your friend! I think you have to hit Gir Draxon 6 times, and he's got triple shots, super speed and invisibility.
I actually prefer boulderdash with the speed a little less at 0.8 or 0.9 making Rockford easier to control.
https://www.atarimagazines.com/cva/v1n1/joysticks.php
or if you want the original source of the article:
https://archive.org/details/Video_Arcade_Games_Vol_1_No_1_1983-09_Creative_Computing_US/page/n101
It's a bit of a hack, but it's more of a proof of concept than anything else. You can switch the gameport from normal to sirius joyport on the fly which is useful.
Boulderdash with the Startup Screen where you can select the Joyport by pressing J.
Stellar 7 controls screen, you can select the Joyport with CTRL+A.
The games that I've found to work with the Sirius Joyport are:
Berzap!
Borg
Wavy Navy
Seadragon
Boulder Dash 1, Boulder Dash 2
Dino Eggs
Bouncing Kamungas
Lunar Leeper
Roundabout
Pest Patrol
Jawbreaker II
Vindicators (CTRL+M)
Miner 2049er, Miner II
Stellar 7
Outpost
Fly Wars
Lemmings
Plasmania
Stellar 7 really gets fast and furious with ramping the speed up to 1.5 or 2.0. What a superb game.
./mame64 apple2p stellar7 -speed 2.0
I can only finish the game with save states! Shift+F7 and F7 are your friend! I think you have to hit Gir Draxon 6 times, and he's got triple shots, super speed and invisibility.
I actually prefer boulderdash with the speed a little less at 0.8 or 0.9 making Rockford easier to control.
Monday, January 7, 2019
Miner 2049er II for apple 2
I got inspired to play miner 2 after watching some playthrough videos on youtube. I think I understand why I never was able to finish miner 2049er back in the day, it was just too tedious and unforgiving. It's a heck of a lot easier with savestates. I consider finishing one level an achivement.
Once you complete the 10 screens, it becomes near impossible with the stupid bouncy ball showing up unexpectedly.
Here's some cheats in the mame debugger:
set your score (you only see 7 digits)
d@080c=87654321
set the amount of time remaining, here it will be 99 minutes 60 seconds
w@0808=9960
If you set it too high, when you finish the level it can take a long time to count down, so just do
w@0808=0100
number of blocks remaining to cover, set it to zero to finish the level
b@080a=00
number of lives, don't set above 21 (0x15) or the hats will cover up the screen
b@081c=15
./mame64 apple2e -flop1 "~/Downloads/Miner 2049er II (4am crack).zip/Miner 2049er II (4am crack)/Miner 2049er II (4am crack).dsk" -window -confirm_quit -debug
There's a couple of interesting things I discovered while using the mame debugger.
I tried to disable a watchpoint numbered 0xA with wpdisable A but it didn't work.
What was happening is that it was interpreting A to mean the current value of the accumulator.
To workaround this, just do wpdisable 0xA.
If you want to flip to the hi res page 2 manually, do
b!c055=1
And to flip back to hi res page 1, do
b!c054=1
and here's a lua function to calculate the beginning address of each line of the hi-res screen: It's useful when you want to set a watchpoint at a specific point on screen.
function calc(line) return line % 8 * 1024 + math.floor(line / 64) * 40 + math.floor((line%64) / 8) * 128 +8192 end
for i = 0,191 do print(i,string.format("%x",calc(i))) end
and here's an example of writing directly to the apple's memory from lua:
cpu = manager:machine().devices[":maincpu"];mem = cpu.spaces["program"]
for i = 0,191 do mem:write_u8(calc(i),i) end
Subscribe to:
Posts (Atom)