OK, I'm going to dare to jump into this discussion.
When I was a kid, I dreamed about being able to program in machine code, but never got anywhere - no useful books, routines, examples, or assembler in my possession.
However, I did write some pretty involved BASIC programs, and even graduated into the very slightly more complex (albeit somewhat buggy) BASIC of the SAM Coupe - what with its separate screen display pages, scrolling, and what not. But since then, I've not touched anything Spectrum until discovering this site a few months ago. :)
Upon reentry, I'm now using MacOSX and FUSE for emulation of games.
Now - can anybody recommend, or point me in the right direction of:
1/ a good modern BASIC editor (or should I just use FUSE?).
2/ my best route into editing and writing Z80 machine code (on a Mac).
3/ links to online (pdf or html) Z80 machine code books or example codes.
There is a lot of useful information in this thread, and I am still reading through the many posts - but any further (perhaps Mac-specific) info will be really helpful.
Just use TORNADO in FUSE for your Z80 coding.
A nice editor and compiler together.
You won't be coding miles of code right away.
Other advantage: You can use FUSE's debugger to see what the registers in your code will do. Just place a stop at the begin of your code and then single step your code. When ready press continue.
good thread! I'm currently doing a lot of stuff in Java for uni but have always wanted to learn machine code for the speccy but never knew where to start. I was fairly decent with BASIC back in the day but my games were sketchy at best!
Now - can anybody recommend, or point me in the right direction of:
1/ a good modern BASIC editor (or should I just use FUSE?).
2/ my best route into editing and writing Z80 machine code (on a Mac).
As Kiwi said, BASin is probably the best thing for this. If you can run it in a virtual machine then you'd be able to use the BASIC and Z80 Assembly editors. You don't need a full WindowsXP installation - BASin will run in Windows 98 quite comfortably. If you're feeling brave, then the source code for BASin comes with the distribution, so porting to Mac might be an option...
3/ links to online (pdf or html) Z80 machine code books or example codes.
There's several PDF books available here on this very archive.
Beware that some of the books are just a load of scanned images bundled into PDF files, and so are quite large. Some people *have* taken the time to OCR them into text though, but there's not many.
No joy here. It asks me for username+password. My WoS ones do not work for me. Ordered the William Tang book yesterday - but it may take a while to arrive - pointers to other online resources would be great.
Just use TORNADO in FUSE for your Z80 coding.
A nice editor and compiler together.
You won't be coding miles of code right away.
Other advantage: You can use FUSE's debugger to see what the registers in your code will do. Just place a stop at the begin of your code and then single step your code. When ready press continue.
Thanks, Dr Beep. I'll give TORNADO a go. But I have to admit to already being somewhat lost by your terms "registers" and "stop". This is how BASIC-oriented and as yet non-machine code my brain is. I definitely need some books. And a list of assembly language definitions.
More generally - it seems to me that the best way to learn machine code would be starting with pre-written simple routines - for say printing something on screen - then playing around to see what I can do to modify it / break it / etc.
Anyone have a chunk of (VERY) simple code they'd like to donate??
I also imagine conversion of simple BASIC programs that I write might also be informative... any thoughts here?
Not a Basic editor itself, but if you want to hack Basic in the text editor of your choice then ZMakeBas will convert your text files into runnable form. Works for me (although I've never developed a full-scale Basic program from scratch with it - only loader routines and pre-existing type-ins.)
Bas2tap apparently does the same thing, but I haven't tried it.
Not a Basic editor itself, but if you want to hack Basic in the text editor of your choice then ZMakeBas will convert your text files into runnable form. Works for me (although I've never developed a full-scale Basic program from scratch with it - only loader routines and pre-existing type-ins.)
Bas2tap apparently does the same thing, but I haven't tried it.
Thanks, but I seem to be doing something wrong - unable to collect anything via links to the ftp sites. Is this normal? I just get a: "preparing to download", then sometime later a: "timed out" message with nothing transferred. Should I be connecting to the ftp sites in a different way then just clicking the link?
Edit: OK. Now on ethernet connection and all is well - doesn't like Airport for some reason.
Thanks, Dr Beep. I'll give TORNADO a go. But I have to admit to already being somewhat lost by your terms "registers" and "stop". This is how BASIC-oriented and as yet non-machine code my brain is. I definitely need some books. And a list of assembly language definitions.
I can warmly recommend Pasmo for compiling z80 assembly on the Mac. It's a terminal application that takes a text file as input and compiles to a tzx file. You can just write your code in your favorite MacOS text editor (SubEthaEdit or BBEdit for instance) and load the result directly in Fuse. No hassle when the code crashes your Speccy! And all the luxuries of copy/paste when writing your code. :)
For extra convenience I wrote a droplet where you can drop the text file on and pasmo automatically compiles it. Let me know if you want to use it.
I can warmly recommend Pasmo for compiling z80 assembly on the Mac. It's a terminal application that takes a text file as input and compiles to a tzx file. You can just write your code in your favorite MacOS text editor (SubEthaEdit or BBEdit for instance) and load the result directly in Fuse. No hassle when the code crashes your Speccy! And all the luxuries of copy/paste when writing your code. :)
For extra convenience I wrote a droplet where you can drop the text file on and pasmo automatically compiles it. Let me know if you want to use it.
Many thanks Paul. Pasmo sounds like just what I would like to use as part of my z80 assembly workflow. And your link gave me links to lots of other very useful documentation lists that should help me learn a lot :-)
Only prob...I'm ashamed to admit that I never have once used the terminal application, so am clueless how to get it to compile a tzx (even with your readme).
The droplet you describe, however, sounds great - please post it if you can.
Ok, here goes. Paste this in Script editor, compile it and save as application in the Pasmo folder. Drop your source files (ending with .asm) on it to let Pasmo compile it and create a tzx file.
(*
Pasmo droplet
Feeds text files ending with .asm to Pasmo to create a tzx file
Paul van der Laan, 2005-12-14
*)
-- Split a string and return list
on splitString(t, myDelimiter)
set text item delimiters of AppleScript to myDelimiter
set l to text items of t
set AppleScript's text item delimiters to {""} -- restore delimiters to default value
return l
end splitString
-- Join a list and return string
on joinList(l, myDelimiter)
set text item delimiters of AppleScript to myDelimiter
set t to l as text
set AppleScript's text item delimiters to {""} -- restore delimiters to default value
return t
end joinList
on feedPasmo(fileAlias)
set pasmoPath to path to me as text
set pasmoPath to (items 1 thru -2 of my splitString(pasmoPath, ":")) & "pasmo"
set pasmoPath to my joinList(pasmoPath, ":")
set pasmoPath to quoted form of POSIX path of pasmoPath
set fullPath to fileAlias as text
set splitPath to my splitString(fullPath, ".")
-- check extension
ignoring case
if item -1 of splitPath is not "asm" then
display dialog "File has not the extension .asm"
return false
end if
end ignoring
set tzxPath to joinList(items 1 thru -2 of splitPath, ".")
set tzxPath to tzxPath & ".tzx"
set fullPath to quoted form of POSIX path of fullPath
set tzxPath to quoted form of POSIX path of tzxPath
set unixCmd to pasmoPath & " --tzx -v " & fullPath & " " & tzxPath
set myResult to do shell script unixCmd
if myResult is not "" then display dialog myResult
return true
end feedPasmo
on run
set fileAlias to choose file with prompt "Choose z80 source file"
my feedPasmo(fileAlias)
end run
on open of allFiles -- (list met aliasen)
repeat with fileAlias in allFiles
my feedPasmo(fileAlias)
end repeat
end open
However - I have another question (it may just be that i haven't yet got the the relevant section of the books yet), but, when using an assembler, how do you specify where the translated code gets stored?
Does it by default go at the lowest available memory address, or wherever one of the registers is pre loaded with?
e.g. I tried a very simple program in Tornado that I was attempting to get to turn address 16384 solid black (255) - like mimicking POKE 16384, 255. It assembled without error (apparently ;)) in Tornado, but where is it stored?
I assume Pasmo will also store code at a specific address somewhere in a similar way. Does it by default, autorun? I guess I can try it out...
In the case of Tornado, there are actually two directives to supply: ORG and DUMP. ORG tells the assembler the starting address to calculate labels from (so that it knows the addresses to put into JP / CALL and friends), and DUMP tells it where to put the code.
(Normally you'd put the same address for both, although occasionally you might want to assemble your code to somewhere in memory that's taken up by the assembler - in which case you'd DUMP it somewhere temporary and move it later.)
(Normally you'd put the same address for both, although occasionally you might want to assemble your code to somewhere in memory that's taken up by the assembler - in which case you'd DUMP it somewhere temporary and move it later.)
Or if you're writing a replacement ROM, or are writing something that's resident on the screen$.
Followup: So, I assume you can specify multiple ORG and DUMP instructions throughout some assembly code to get discrete sections in discrete memory locations - correct?
Paul: does Pasmo use ORG and DUMP?
In any case, currently I cannot get Pasmo to work correctly. Whatever I write in BBedit (saved to .asm file) and dropped on Pasmo, creates a tzx file, that when run just Prints: "Bytes: /Users/XXX" on and on down the screen... Where XXX are the first 3 letters of my home folder.
If I understand the memory browser of FUSE correctly, this data seems to have been assembled around 5CE0h (23776).
Yes, Pasmo uses ORG. I'm not sure about DUMP, but you should check the Pasmo documentation for that.
Do you use LOAD "" CODE when running your tzx? Because that's what you're supposed to do when loading machine code. Suppose you specified ORG 64000 in your source, then enter these commands in Fuse:
CLEAR 63999
LOAD "" CODE
RANDOMIZE USR 64000
BTW - Are you familiar enough with the way the Spectrum works? You might need additional information like the Sinclair Basic manual to get a better grasp of it.
BTW - Are you familiar enough with the way the Spectrum works? You might need additional information like the Sinclair Basic manual to get a better grasp of it.
I'm reading everything I can get my hands on at the moment...much of the BASIC, and organisation of the Spectrum RAM (like the screen addresses, etc) are coming back to me...slowly.
Pasmo does not work that way. ORG stablishes the position for both code generation and position, and you can use the .PHASE directive to alter generation.
In any case, currently I cannot get Pasmo to work correctly.
If you want to create a tzx or tap that starts the program automatically you must use the directives ORG to position the code and END with argument to define the entry point, and use the --tapbas or --tzxbas command line options.
If not, elaborate what you mean by "work correctly"
I just double-click the tzx, and it opens up FUSE and runs with the repeating printed text.
As Paul noted you are going about this the wrong way. Loading a machine code routine requires a little setup in BASIC first. The TZX file you've created from Pasmo has the machine code in an entry called Bytes: xxx. Fuse or any emulator for that matter will not load this in because it doesn't know *how* to load it in.
If you load in some of the Speccy machinec code games you will notice that the first thing that is loaded in is a short BASIC program called Program xxx. This sets up the machine code and then the machine code is loaded in from the Bytes xxx. Since your TZX doesn't have the Program header it just keeps looping thru the TZX trying to find it.
Anyhow, what you need to do is to do the setup yourself and then load in the machine code. So, before you try to load in the TZX, do the steps given by Paul substistuting the addresses for your code as required and then load in the TZX. It should work.
Well - it turns out there were multiple problems - but I fixed them with trial and error last night.
#1 - as Paul said: autoload was on.
#2 - as made explicit by Arjun, I needed to write a BASIC header/loader (it now loads and executes files at 49152)
#3 - i was saving the BBEdit files as Macintosh - not Unix. For whatever reason they were creating empty tzx, with no code to execute.
Now all is good :) I even got the border to change colour!
...and the piece de resistance...
org 49152
a1 ld a,255
ld b,a
ld a,7
ld c,a
loop ld a,255
ld b,a
ld a,c
ld de,18432
loop1 ld (de),a
inc de
djnz loop1
ld (de),a
a4 ld a,c
rlca
ld c,a
jp loop
ret
It's pretty crap, and you have to quit to stop it, but what the hell - my first real routine! :D
Comments
I'm pretty sure it would run in a Virtual machine if you have something like that available on your mac.
Sorry can't help much on 2 and 3, probably wasn't much help for 1 either ;-)
Just use TORNADO in FUSE for your Z80 coding.
A nice editor and compiler together.
You won't be coding miles of code right away.
Other advantage: You can use FUSE's debugger to see what the registers in your code will do. Just place a stop at the begin of your code and then single step your code. When ready press continue.
As Kiwi said, BASin is probably the best thing for this. If you can run it in a virtual machine then you'd be able to use the BASIC and Z80 Assembly editors. You don't need a full WindowsXP installation - BASin will run in Windows 98 quite comfortably. If you're feeling brave, then the source code for BASin comes with the distribution, so porting to Mac might be an option...
There's several PDF books available here on this very archive.
ftp://ftp.worldofspectrum.org/pub/sinclair/books/
Beware that some of the books are just a load of scanned images bundled into PDF files, and so are quite large. Some people *have* taken the time to OCR them into text though, but there's not many.
A lot of the scans are quite ropey too.
D.
Specifics: no Virtual PC, so unless i buy it, no Windows=No BASin, so still looking for a more equipped BASIC editor for OSX... No idea where to start with this, but thanks for the suggestion.
No joy here. It asks me for username+password. My WoS ones do not work for me. Ordered the William Tang book yesterday - but it may take a while to arrive - pointers to other online resources would be great.
Thanks, Dr Beep. I'll give TORNADO a go. But I have to admit to already being somewhat lost by your terms "registers" and "stop". This is how BASIC-oriented and as yet non-machine code my brain is. I definitely need some books. And a list of assembly language definitions.
More generally - it seems to me that the best way to learn machine code would be starting with pre-written simple routines - for say printing something on screen - then playing around to see what I can do to modify it / break it / etc.
Anyone have a chunk of (VERY) simple code they'd like to donate??
I also imagine conversion of simple BASIC programs that I write might also be informative... any thoughts here?
www.worldofspectrum.org/Z80.html
thanking you kindly :)
By the way - trying to run Tornado.TAP in FUSE gives me: C Nonsense in BASIC, 9000:3
Edit: Fixed it by removing * in the LOAD command.
Bas2tap apparently does the same thing, but I haven't tried it.
Thanks, but I seem to be doing something wrong - unable to collect anything via links to the ftp sites. Is this normal? I just get a: "preparing to download", then sometime later a: "timed out" message with nothing transferred. Should I be connecting to the ftp sites in a different way then just clicking the link?
Edit: OK. Now on ethernet connection and all is well - doesn't like Airport for some reason.
For extra convenience I wrote a droplet where you can drop the text file on and pasmo automatically compiles it. Let me know if you want to use it.
Many thanks Paul. Pasmo sounds like just what I would like to use as part of my z80 assembly workflow. And your link gave me links to lots of other very useful documentation lists that should help me learn a lot :-)
Only prob...I'm ashamed to admit that I never have once used the terminal application, so am clueless how to get it to compile a tzx (even with your readme).
The droplet you describe, however, sounds great - please post it if you can.
(* Pasmo droplet Feeds text files ending with .asm to Pasmo to create a tzx file Paul van der Laan, 2005-12-14 *) -- Split a string and return list on splitString(t, myDelimiter) set text item delimiters of AppleScript to myDelimiter set l to text items of t set AppleScript's text item delimiters to {""} -- restore delimiters to default value return l end splitString -- Join a list and return string on joinList(l, myDelimiter) set text item delimiters of AppleScript to myDelimiter set t to l as text set AppleScript's text item delimiters to {""} -- restore delimiters to default value return t end joinList on feedPasmo(fileAlias) set pasmoPath to path to me as text set pasmoPath to (items 1 thru -2 of my splitString(pasmoPath, ":")) & "pasmo" set pasmoPath to my joinList(pasmoPath, ":") set pasmoPath to quoted form of POSIX path of pasmoPath set fullPath to fileAlias as text set splitPath to my splitString(fullPath, ".") -- check extension ignoring case if item -1 of splitPath is not "asm" then display dialog "File has not the extension .asm" return false end if end ignoring set tzxPath to joinList(items 1 thru -2 of splitPath, ".") set tzxPath to tzxPath & ".tzx" set fullPath to quoted form of POSIX path of fullPath set tzxPath to quoted form of POSIX path of tzxPath set unixCmd to pasmoPath & " --tzx -v " & fullPath & " " & tzxPath set myResult to do shell script unixCmd if myResult is not "" then display dialog myResult return true end feedPasmo on run set fileAlias to choose file with prompt "Choose z80 source file" my feedPasmo(fileAlias) end run on open of allFiles -- (list met aliasen) repeat with fileAlias in allFiles my feedPasmo(fileAlias) end repeat end openHowever - I have another question (it may just be that i haven't yet got the the relevant section of the books yet), but, when using an assembler, how do you specify where the translated code gets stored?
Does it by default go at the lowest available memory address, or wherever one of the registers is pre loaded with?
e.g. I tried a very simple program in Tornado that I was attempting to get to turn address 16384 solid black (255) - like mimicking POKE 16384, 255. It assembled without error (apparently ;)) in Tornado, but where is it stored?
I assume Pasmo will also store code at a specific address somewhere in a similar way. Does it by default, autorun? I guess I can try it out...
Use the ORG directive to tell the assembler where to store the code. for ex,
ORG 36000 will store your code from address 36000.
Bytes:Chuntey - Spectrum tech blog.
(Normally you'd put the same address for both, although occasionally you might want to assemble your code to somewhere in memory that's taken up by the assembler - in which case you'd DUMP it somewhere temporary and move it later.)
Followup: So, I assume you can specify multiple ORG and DUMP instructions throughout some assembly code to get discrete sections in discrete memory locations - correct?
Paul: does Pasmo use ORG and DUMP?
In any case, currently I cannot get Pasmo to work correctly. Whatever I write in BBedit (saved to .asm file) and dropped on Pasmo, creates a tzx file, that when run just Prints: "Bytes: /Users/XXX" on and on down the screen... Where XXX are the first 3 letters of my home folder.
If I understand the memory browser of FUSE correctly, this data seems to have been assembled around 5CE0h (23776).
Any thoughts?
Do you use LOAD "" CODE when running your tzx? Because that's what you're supposed to do when loading machine code. Suppose you specified ORG 64000 in your source, then enter these commands in Fuse:
CLEAR 63999
LOAD "" CODE
RANDOMIZE USR 64000
BTW - Are you familiar enough with the way the Spectrum works? You might need additional information like the Sinclair Basic manual to get a better grasp of it.
I just double-click the tzx, and it opens up FUSE and runs with the repeating printed text.
Thanks - the Spectrum manual is a little thin in this area
I'm reading everything I can get my hands on at the moment...much of the BASIC, and organisation of the Spectrum RAM (like the screen addresses, etc) are coming back to me...slowly.
Pasmo does not work that way. ORG stablishes the position for both code generation and position, and you can use the .PHASE directive to alter generation.
If you want to create a tzx or tap that starts the program automatically you must use the directives ORG to position the code and END with argument to define the entry point, and use the --tapbas or --tzxbas command line options.
If not, elaborate what you mean by "work correctly"
As Paul noted you are going about this the wrong way. Loading a machine code routine requires a little setup in BASIC first. The TZX file you've created from Pasmo has the machine code in an entry called Bytes: xxx. Fuse or any emulator for that matter will not load this in because it doesn't know *how* to load it in.
If you load in some of the Speccy machinec code games you will notice that the first thing that is loaded in is a short BASIC program called Program xxx. This sets up the machine code and then the machine code is loaded in from the Bytes xxx. Since your TZX doesn't have the Program header it just keeps looping thru the TZX trying to find it.
Anyhow, what you need to do is to do the setup yourself and then load in the machine code. So, before you try to load in the TZX, do the steps given by Paul substistuting the addresses for your code as required and then load in the TZX. It should work.
Bytes:Chuntey - Spectrum tech blog.
#1 - as Paul said: autoload was on.
#2 - as made explicit by Arjun, I needed to write a BASIC header/loader (it now loads and executes files at 49152)
#3 - i was saving the BBEdit files as Macintosh - not Unix. For whatever reason they were creating empty tzx, with no code to execute.
Now all is good :) I even got the border to change colour!
...and the piece de resistance...
org 49152
a1 ld a,255
ld b,a
ld a,7
ld c,a
loop ld a,255
ld b,a
ld a,c
ld de,18432
loop1 ld (de),a
inc de
djnz loop1
ld (de),a
a4 ld a,c
rlca
ld c,a
jp loop
ret
It's pretty crap, and you have to quit to stop it, but what the hell - my first real routine! :D
Thanks for all the help.