Learning Machine Code
Re: Learning Machine Code
I've mentioned this previously, but this three part tutorial from [mention]Shaun_B[/mention] really gave me the introduction I needed. It originally appeared in MicroMart magazine.
http://shaunbebbington.blogspot.com/201 ... i.html?m=1
You just need Pasmo which is an opensource command line assembler, notepad and an emulator.
http://shaunbebbington.blogspot.com/201 ... i.html?m=1
You just need Pasmo which is an opensource command line assembler, notepad and an emulator.
Re: Learning Machine Code
Excellent and thank you I will also add this to the list of learning tools. Also thanks again to joefish, I had not realised zxspin could be run from command line so I have now edited the batch file run from Notepad++ to start Z Spin and load in the newly created .tap file from Pasmo. My Batch file is called RunPasmo.batPeterJ wrote: ↑Fri Jan 17, 2020 7:15 am I've mentioned this previously, but this three part tutorial from @Shaun_B really gave me the introduction I needed. It originally appeared in MicroMart magazine.
http://shaunbebbington.blogspot.com/201 ... i.html?m=1
You just need Pasmo which is an opensource command line assembler, notepad and an emulator.
Code: Select all
@ECHO OFF
REM NotePad RUN command "drive:\filepath\RunPasmo.bat $(FULL_CURRENT_PATH)"
REM $(FULL_CURRENT_PATH) is a command from Notepad++ for full path to current file
REM %~n1 Extracts file name without the type from $(FULL_CURRENT_PATH)
REM %dp1 Extracts just the file path from $(FULL_CURRENT_PATH)
REM Pasmo command line
E:\personal\computer\ZXSpectrum48K\programing\pasmo-0.5.3\pasmo-0.5.3\pasmo.exe --name %~n1 --tapbas %~dp1\%~n1.asm %~dp1\%~n1.tap
REM Make new directory in the path wher the .asm file is called TAP
MKDIR %~dp1\TAP
REM Put the new created .tap file in the directory TAP
MOVE %~dp1\*.tap %~dp1\TAP
REM Launch Spin
E:\personal\computer\ZXSpectrum48K\emulator\zxspin_0666emu\ZXSpin.exe %~dp1Tap\%~n1.tap
Re: Learning Machine Code
I have a question about knowing where in your code subroutines are. It really harks back to OpCodes and Assemblers vs Directly entering Hex. I expect I know the answer but I find it hard to believe
So if you look at page 93 of Mastering Machine Code -> https://spectrumcomputing.co.uk/index.p ... id=2000237 here Toni Baker writes an example routine for scrolling the screen up or down. I have published my .asm file below. Please note I added the ORG 32768.
She then provides the Basic program to use the Machine Code. In the Basic Program depending on keyboard key "7" or "6" being pressed - lines 160 and 150 - the Machine Code subroutines UP or DOWN are called. Of course she has not instructed you where (memory location) to build the Machine code to - in my case I used 32768 - which means she can only tell you where in the code sub-routine up and sub-routine down are by referencing the labels UP and DOWN so she states USR up and USR down at the relevant points. In order to get it working I added the reference USR 32841 and USR 32779 at the correspond position in Basic, but I only know these locations by actually counting the Bytes used in the code - referencing page 93 above I literally count the bytes from 32768 onwards until I reach Label UP and Label Down.
The question is - Is there a way of knowing by looking at the OPcode above what the byte count is to a specific point in your code or do you just need to keep track? If you need to keep track how would you do this in a large program like ManicMiner or Elite?
I do hope that makes sense.
So if you look at page 93 of Mastering Machine Code -> https://spectrumcomputing.co.uk/index.p ... id=2000237 here Toni Baker writes an example routine for scrolling the screen up or down. I have published my .asm file below. Please note I added the ORG 32768.
Code: Select all
ORG 32768
UPLD PUSH BC
PUSH DE
PUSH HL
LDIR
POP HL
INC H
POP DE
INC D
POP BC
RET
UP LD HL,#4020
LD DE,#4000
LD BC,#1AE0
LDIR
LD HL,#47E0
LD DE,#40E0
LD C,#20
LD A,#10
U_LOOP CALL UPLD
DEC A
JR NZ,U_LOOP
LD H,D
LD E,#E1
DEC BC
LD A,#08
U_BLANK LD (HL),#00
CALL UPLD
DEC A
JR NZ,U_BLANK
LD H,#5A
LD D,H
LD A,(#5C48);bordcr
LD (HL),A
LDIR
RET
DOWNLD PUSH BC
PUSH DE
PUSH HL
LDDR
POP HL
DEC H
POP DE
DEC D
POP BC
RET
DOWN LD HL,#5ADF
LD DE,#5AFF
LD BC,#1AE0
LDDR
LD HL,#501F
LD DE,#571F
LD C,#20
LD A,#10
D_LOOP CALL DOWNLD
DEC A
JR NZ,D_LOOP
LD H,D
LD E,#1E
DEC BC
LD A,#08
D_BLANK LD (HL),#00
CALL DOWNLD
DEC A
JR NZ,D_BLANK
LD H,#58
LD D,H
LD A,(#5C8D);ATTR_P
LD (HL),A
LDDR
RET
The question is - Is there a way of knowing by looking at the OPcode above what the byte count is to a specific point in your code or do you just need to keep track? If you need to keep track how would you do this in a large program like ManicMiner or Elite?
I do hope that makes sense.
Code: Select all
10 DIM A$(22,36)
20 FOR I = 1 TO 22
30 LET B$ = CHR$ (INT (96*RND) + 32)
40 FOR J = 0 TO 5
50 LET B$ = B$ + B$
60 NEXT J
70 LET A$(I) = CHR$ 16 + CHR$ INT (8*RND) + CHR$ 17 + CHR$ INT(8*RND) + B$
80 PRINT A$(l)
90 NEXT I
100 LET A = 1
110 PAUSE 0
120 LET B$ = lNKEY$
130 LET B = A + 1 :IF B = 23 THEN LET B = 1
140 LET C = A – 1 :IF C = 0 THEN LET C = 22
150 IF B$ = "6" THEN PRINT AT 0,USR down;A$(C): LET A = C
160 IF B$ = "7" THEN PRINT AT 21,USR up; A$(A): LET A = B
170 INPUT ""
180 GO TO 110
Re: Learning Machine Code
PASMO has an option to let you save out the 'Symbol Table' during compilation.
This dumps the value of every variable (and thus location of every label), in alphabetical order, to a text file at the end of compilation.
I sometimes use it to calculate the size of the code or data by putting a label at the beginning and end, calculating a variable from the difference, and giving it a name like a taxi firm ("___A1A!!!AAA_TAXIS") so it appears high up in the alphabetical list.
(Which reminds me of the most obscure joke in an animation ever seen - the sign for "Thigmo Taxis" on the side of a building during a chase scene in Little Rodentia in Disney's Zootropolis / Zootopia. "Thigmotaxis" is the tendency of rodents to run alongside walls instead of out in the open. Rather than being some sort of rodent agoraphobia, they've actually evolved a reassuring tactile sensation ('thigmo' = 'tactile') when moving along a wall ('taxis' = 'movement', Ancient Greek) on one or the other side of their body; it's quite literally how they get from one place to another).
This dumps the value of every variable (and thus location of every label), in alphabetical order, to a text file at the end of compilation.
I sometimes use it to calculate the size of the code or data by putting a label at the beginning and end, calculating a variable from the difference, and giving it a name like a taxi firm ("___A1A!!!AAA_TAXIS") so it appears high up in the alphabetical list.
(Which reminds me of the most obscure joke in an animation ever seen - the sign for "Thigmo Taxis" on the side of a building during a chase scene in Little Rodentia in Disney's Zootropolis / Zootopia. "Thigmotaxis" is the tendency of rodents to run alongside walls instead of out in the open. Rather than being some sort of rodent agoraphobia, they've actually evolved a reassuring tactile sensation ('thigmo' = 'tactile') when moving along a wall ('taxis' = 'movement', Ancient Greek) on one or the other side of their body; it's quite literally how they get from one place to another).
Re: Learning Machine Code
Thanks Joefish, I’ll take a look later.
Re: Learning Machine Code
Another trick is to start your code with a series of JP instructions to the entry points. Since each is three bytes long the addresses are easily predictable and won't move each time you reassemble the listing.
Re: Learning Machine Code
That should work really well for this. Thanks
Re: Learning Machine Code
Hi All,
So I have been busily working my way through some examples. Feeling quite good but with lots to learn and then today I got hit with something that I had assumed I knew …
ORG 32768
I thought that this statement meant that my code would start at the address 32768 and then in order to execute that code I then input RANDOMIZE USR 32768. So this all works, but tonight I needed to shift the code 54bytes higher so I did
ORG 32822 and then RANDOMIZE USR 32822 and I get an error - same code as before. Then when I type RANDOMIZE USR 32768 it all runs as expected??? Have I miss understood the ORG and if so how would I decide where to put machine code in the memory?
For reference here is the code. Not very exciting and needs a CLR before running...
Ideally it requires
700 RANDOMIZE USR 32768
710 INPUT LINE A$
720 RANDOMIZE USR 32781
Then it allows you to enter co-ords - nothing happens except you can enter more co-ords the actual move sub will come once I can relocate the code to a new part of the machine i.e. 32822
Thanks for any and all input.
So I have been busily working my way through some examples. Feeling quite good but with lots to learn and then today I got hit with something that I had assumed I knew …
ORG 32768
I thought that this statement meant that my code would start at the address 32768 and then in order to execute that code I then input RANDOMIZE USR 32768. So this all works, but tonight I needed to shift the code 54bytes higher so I did
ORG 32822 and then RANDOMIZE USR 32822 and I get an error - same code as before. Then when I type RANDOMIZE USR 32768 it all runs as expected??? Have I miss understood the ORG and if so how would I decide where to put machine code in the memory?
For reference here is the code. Not very exciting and needs a CLR before running...
Ideally it requires
700 RANDOMIZE USR 32768
710 INPUT LINE A$
720 RANDOMIZE USR 32781
Then it allows you to enter co-ords - nothing happens except you can enter more co-ords the actual move sub will come once I can relocate the code to a new part of the machine i.e. 32822
Thanks for any and all input.
Code: Select all
ORG 32768
JP start ; 3 BYTES
JP move ; 3 BYTES
s_print POP HL ; pulls address off stack
LD A,(HL) ; This refers to first byte of defm
INC HL ; alter +1 return byte address
PUSH HL
AND A ; Reset Carry and Set Zero if 0
RET Z ; when we reach defb #00 return to JP board
RST #10 ; prints message to screen
JR s_print
start XOR A ; A=0, Reset Carry
LD (#5C3C),A ; TVFlag
CALL s_print ; pushes the address of next instruction i.e. the space below onto stack
DEFM " 12345678",#0D
DEFM "1",#90," ",#90," ",#90," ",#90," 1",#0D
DEFM "2 ",#90," ",#90," ",#90," ",#90,"2",#0D
DEFM "3 3",#0D
DEFM "4 4",#0D
DEFM "5 5",#0D
DEFM "6 6",#0D
DEFM "7",#90," ",#90," ",#90," ",#90," 7",#0D
DEFM "8 ",#90," ",#90," ",#90," ",#90,"8",#0D
DEFM " 12345678"
DEFB #00 ;sets the byte to 0 - end sub routine s_print
JP board
row LD A,#04
row_2 LD (HL),C ;color next draughts piece
INC HL
INC HL
DEC A
JR NZ,row_2
ADD HL,DE ;next row
BIT #0,L
JR NZ,row_3
INC HL
INC HL
row_3 DJNZ row
RET
board LD HL,#5800 ;PrintAt 0,0 attribute
LD DE,#0016
LD C,#0A
yellow_1 LD B,#0A ;B=10 row 2 yellow, 4 black 4 white
yellow_2 LD (HL),#30
INC HL
DJNZ yellow_2
ADD HL,DE
DEC C
JR NZ,yellow_1
LD HL,#5821
LD E,#18
LD C,#08
white_1 LD B,#08
white_2 LD (HL),#38
INC HL
DJNZ white_2
ADD HL,DE
DEC C
JR NZ,white_1
LD HL,#5822
DEC E
LD BC,#0307
CALL row
LD BC,#0200
CALL row
LD BC,#0302
CALL row
RET
move LD HL,(#5C4B) ;VARS system variable
INC HL
LD E,(HL)
INC HL
INC HL
LD A,(HL)
CP #E2 ;STOP Sym A
JR NZ,a$_ok
RST #08
DEFB #FF
a$_ok LD HL,#02C6
LD (#5C42),HL
LD A,#01
LD(#5C44),A
RET
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Learning Machine Code
Assembler directives and pseudo-instructions are pretty specific to a particular flavor of assembler, so it’s hard to tell without knowing your setup. I quickly tried your code in zasm and, after a tiny bit of cleanup, it worked fine. I could easily relocate your code anywhere in RAM (not that anything would suggest I couldn’t).
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Re: Learning Machine Code
Of course should have realised. I am using Pasmo as the assembler and and standard text editor to write the assembly. It’s running through ZX Spin.
Thanks for running the code and glad it worked I am now thinking I should use hex instead of decimal in the ORG statement - I’ve had issues in the code with decimal.
It’s all shut down now but I will try it tomorrow.
Thanks for running the code and glad it worked I am now thinking I should use hex instead of decimal in the ORG statement - I’ve had issues in the code with decimal.
It’s all shut down now but I will try it tomorrow.
Re: Learning Machine Code
Why USR 32781 ? Where it should jump ?
Anyway, I'm not seeing any issues with your code. Still, I would not use $ in label, it can have special meaning.
Anyway, I'm not seeing any issues with your code. Still, I would not use $ in label, it can have special meaning.
Proud owner of Didaktik M
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Learning Machine Code
I see. Well, I’m not familiar with either, but off the top of my head, I’d suggest putting a space in front of the ORG statement. Some assemblers assume that a letter at the first position of a line is a label, rather than a (pseudo-) instruction/directive.
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
- lister_of_smeg
- Microbot
- Posts: 145
- Joined: Thu Nov 16, 2017 1:44 pm
Re: Learning Machine Code
Yup, this. And as this results in you having no defined origin, I would hazard a guess that Pasmo defaults to 32768 in such a case.Ast A. Moore wrote: ↑Tue Jan 28, 2020 10:20 pm I see. Well, I’m not familiar with either, but off the top of my head, I’d suggest putting a space in front of the ORG statement. Some assemblers assume that a letter at the first position of a line is a label, rather than a (pseudo-) instruction/directive.
Re: Learning Machine Code
Hey I did not see these last night and tried the hex before coming to work but that failed.
Will give this a shot tonight
Will give this a shot tonight
Re: Learning Machine Code
Just as a test it appears to work okay for me. Should the you mention 32781 be 32771 ? (to the second jp command) - though this gives a N Statement Lost Error.
Relocating the routine to a different address (different org instead of 32768), and calling it there seems to work the same.
I'm using PASMO on a mac: with these arguments:
pasmo --tapbas try/try.asm try/try.tap
Just as a 'did you know' - finishing your assembly with END 32768 will compile the basic loader so it already does a Randomize 32768 when you launch it in your emulator.
Relocating the routine to a different address (different org instead of 32768), and calling it there seems to work the same.
I'm using PASMO on a mac: with these arguments:
pasmo --tapbas try/try.asm try/try.tap
Just as a 'did you know' - finishing your assembly with END 32768 will compile the basic loader so it already does a Randomize 32768 when you launch it in your emulator.
CLEAR 23855
- Alessandro
- Dynamite Dan
- Posts: 1910
- Joined: Wed Nov 15, 2017 11:10 am
- Location: Messina, Italy
- Contact:
Re: Learning Machine Code
It doesn't. If you do not specify any code beginning address with ORG in the source, Pasmo will produce, when assembling to a tape image file, a Bytes header stating address 0 as the first location, and all relative jumps in the code will take that into account.lister_of_smeg wrote: ↑Tue Jan 28, 2020 10:52 pm Yup, this. And as this results in you having no defined origin, I would hazard a guess that Pasmo defaults to 32768 in such a case.
Re: Learning Machine Code
Ast A. Moore wrote: ↑Tue Jan 28, 2020 10:20 pm I see. Well, I’m not familiar with either, but off the top of my head, I’d suggest putting a space in front of the ORG statement. Some assemblers assume that a letter at the first position of a line is a label, rather than a (pseudo-) instruction/directive.
Thank you Gents,
Not only did the space before ORG do the trick, but I got an awsome tip from Uglifruit as well.
Back to trying to understand whats going on
Re: Learning Machine Code
I remember years ago as a teenager people said you needed to be good at maths to be a programmer. Many years later I quite happily did web work, SQL, C#, DotNet etc and never found that maths played a significant part.
Now I get it, hex to dec to bin plus the relationships to the screen and attributes to hex and bin rra rrl wtf;). I’ve not yet got settled with understanding these relationships but I can see them and I can work my way through them but they don’t come naturally.
Now I get it, hex to dec to bin plus the relationships to the screen and attributes to hex and bin rra rrl wtf;). I’ve not yet got settled with understanding these relationships but I can see them and I can work my way through them but they don’t come naturally.
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Learning Machine Code
That’s probably because there’s nothing inherently natural about hexadecimal or binary. Come to think of it, this is also true for the decimal system; we’re just familiar with it. (Well, we do have ten fingers and toes, but then there are cultures that don’t use base 10 counting systems.)Hedge1970 wrote: ↑Sat Feb 08, 2020 10:14 am Now I get it, hex to dec to bin plus the relationships to the screen and attributes to hex and bin rra rrl wtf;). I’ve not yet got settled with understanding these relationships but I can see them and I can work my way through them but they don’t come naturally.
It’s totally fine to mix and match different counting systems throughout your code. I do it all the time. Binary is useful when working with bits (shifts, masks, etc.), hexadecimal is more suited for calculating addresses or working with 16–bit-wide registers, decimal is convenient for working out simple coordinates, score, and other “regular” values.
Advanced math is probably non-essential, but some basic math skills always come in handy.
Here’s a small real-life example of code that uses all three bases:
Code: Select all
ld a,%01000111 ;ATTR: no FLASH, BRIGHT, BLACK PAPER, WHITE INK
ld hl,$5907 ;ATTR address
ld (hl),a
inc l
ld (hl),a
ld b,6 ;counter for a short pause
2$ halt
djnz 2$
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Mastering MC Type In
Hi,
Its been quite a journey over the last few weeks and while there is no light on the horizon just yet, I can at least understand around 70% of the work I am copying. I am making my way through Mastering Machine Code (https://ia800604.us.archive.org/view_ar ... ectrum.pdf)
I am using Spin emulator and Pasmo compiler, whereas in the book the author Toni Baker provides her own machine code writing program and herein lies one of the challenges, that is trying to bridge the gap between what she says to do and what to do in my Pasmo/Spin environment.
Most of the examples and programs have been ok and with a lot of thought and a little tweak I manage to get them running, however this little game has me foxed. Its Chapter 15, Page 243 via the above link.
The code below is very similar to the book and while it may not be 100% the same, the issue I am asking about is perfectly working and copied below - the layout of the "spiral". It looks nothing like a spiral and - I hope I am correct here - the loop to work through the parts of the SPIRAL DEFW statements ( LD B,#0A) is only looping 10 times (0A) whereas there are 20 bytes of data so the program ignores the last 10 bytes? This code is three lines below the START label. For the DEFW statements Ive used both binary and hex and both behave the same way.
In my many many experiments with the code I was able to make this slightly modified version. However I thought I would make use of all 20 bytes and added a new loop called SET_C. But when I implement it I get two spirals but not joined side by side, rather separated. I have looked as hard as I can to understand why and realise that I have no understanding of how the first position of the spiral is .. positioned. If anyone can find it in themselves to help I would love to know, then I will/should be able to create a bigger spiral game screen.
Note in both above and below code I have replaced her #5536 for #5C8F to target the Speccy System Variable (ATTR T)
My Code
Its been quite a journey over the last few weeks and while there is no light on the horizon just yet, I can at least understand around 70% of the work I am copying. I am making my way through Mastering Machine Code (https://ia800604.us.archive.org/view_ar ... ectrum.pdf)
I am using Spin emulator and Pasmo compiler, whereas in the book the author Toni Baker provides her own machine code writing program and herein lies one of the challenges, that is trying to bridge the gap between what she says to do and what to do in my Pasmo/Spin environment.
Most of the examples and programs have been ok and with a lot of thought and a little tweak I manage to get them running, however this little game has me foxed. Its Chapter 15, Page 243 via the above link.
The code below is very similar to the book and while it may not be 100% the same, the issue I am asking about is perfectly working and copied below - the layout of the "spiral". It looks nothing like a spiral and - I hope I am correct here - the loop to work through the parts of the SPIRAL DEFW statements ( LD B,#0A) is only looping 10 times (0A) whereas there are 20 bytes of data so the program ignores the last 10 bytes? This code is three lines below the START label. For the DEFW statements Ive used both binary and hex and both behave the same way.
Code: Select all
ORG 26621
JP start
spiral DEFW #FF,#E0
DEFW #A0,#20
DEFW #AF,#A0
DEFW #A8,#A0
DEFW #AA,#A0
DEFW #AE,#A0
DEFW #A0,#A0
DEFW #BF,#A0
DEFW #80,#20
DEFW #FF,#E0
score_1 DEFM #0D
DEFM "Your "
DEFM "Score "
DEFM "Now "
DEFM "999000"
score_c DEFM #16,#0B,#0F
DEFM "000"
start XOR A
LD (#5C3C),A
LD B,#0A
LD HL,#6800
s_loop LD E,(HL)
INC HL
LD D,(HL)
INC HL
EX DE,HL
r_loop ADD HL,HL
JR C,wall
LD A,#3F
LD (#5C8F),A ;used A to ld 3F
JR prsq
wall LD A,#00
LD (#5C8F),A ;used A to ld 00
prsq LD A,#2B
RST #10
LD A,H
OR L
JR NZ,r_loop
LD A,#0D
RST #10
EX DE,HL
DJNZ s_loop
LD A,#38
LD (#5821),A
LD A,#30
LD (#5C8F),A ;Used A to ld 30
LD HL,#6828 ;score_1
LD B,#15
sc_loop LD A,(HL)
INC HL
RST #10
DJNZ sc_loop
LD HL,#3939
LD(#6841),HL ;score c+3
LD(#6842),HL ;score c+4
LD HL,#5821
LD(#5C92),HL
LD HL,#0000
LD(#5C94),HL
loop LD HL,#6843 ;score_c + 5
deci LD A,(HL)
CP #0F
JR NZ,positive
LD B,#03
reset INC HL
LD (HL),#30
DJNZ reset
RET
positive DEC A
CP #2F
JR NZ,ok
LD (HL),#39 ;REPLACE
DEC HL
JR deci
ok LD (HL),A
LD HL,#683E
LD B,#06
cs_loop LD A,(HL)
INC HL
RST #10
DJNZ cs_loop
LD BC,#0800
delay DEC BC
LD A,B
OR C
JR NZ,delay
CALL #028E
LD A,E
CP #09
JR Z,left
CP #10
JR Z,down
CP #11
JR Z,right
CP #12
JR NZ,loop
up LD DE,#FFE0
JR move
left LD DE,#FFFF
JR move
down LD DE,#0020
JR move
right LD DE,#0001
move LD HL,(#5C94)
LD A,H
OR L
JR Z,move_ok
ADD HL,DE
LD A,H
OR L
JR NZ,loop
move_ok LD HL,(#5C92)
LD A,(HL)
XOR #07
LD (HL),A
ADD HL,DE
LD A,(HL)
XOR #07
LD (HL),A
LD (#5C92),HL
LD HL,#0000
CP #38
JR Z,finish
LD H,D
LD L,E
finish LD (#5C94),HL
LD HL,(#5C92)
LD DE,#5885
SBC HL,DE
RET Z
JP loop
Note in both above and below code I have replaced her #5536 for #5C8F to target the Speccy System Variable (ATTR T)
My Code
Code: Select all
ORG 26621
JP start
score_1 DEFM #0D,"Your "
DEFM "score "
DEFM "now "
DEFM "999000" ;22 letters and spaces
score_c DEFM #16,#0B,#0F ;3
DEFM "000" ;3
spiral DEFW %11111111
DEFW %00000001
DEFW %11111101
DEFW %11000101
DEFW %10010101
DEFW %10110101
DEFW %10100101
DEFW %10111101
DEFW %10000001
DEFW %11111111 ;10 start 26644
start XOR A
LD (#5C3C),A
LD B,#0A
LD HL,#681C ;address of spiral data
set_c LD C,#01
s_loop LD E,(HL)
INC HL
LD D,(HL)
INC HL
EX DE,HL
r_loop ADD HL,HL
JR C,wall
LD A,#3F
LD (#5C8F),A ;ATTR_T 0011 1111 FL BR P2 P1 P0 I2 I1 I0
JR prsq
wall LD A,#00
LD (#5C8F),A ;ATTR_T 0000 0000 FL BR P2 P1 P0 I2 I1 I0
prsq LD A,#2B ;+ character
RST #10
LD A,H
OR L
JR NZ,r_loop
EX DE,HL
LD A,C
DEC C
CP #01
JR NZ,s_loop
LD A,#0D ;return new line
RST #10
DJNZ set_c
LD A,#38
LD (#5821),A
LD A,#30
LD (#5C8F),A ;Black on yellow
LD HL,#6800 ;score_1
LD B,#15
sc_loop LD A,(HL)
INC HL
RST #10
DJNZ sc_loop
LD HL,#3939
LD (#6819),HL ;score_c +3
LD (#681A),HL ;score_c +4
LD HL,#5821
LD(#5C92),HL ;Store current position
LD HL,#0000
LD(#5C94),HL ;Store last move
loop LD HL,#681B ;Score_c + 5
decemal LD A,(HL)
CP #0F
JR NZ,positive
LD B,#03
reset INC HL
LD (HL),#30 ;"0"
DJNZ reset
RET
positive DEC A
CP #2F
JR NZ,ok
LD (HL),#39 ;"9"
DEC HL
JR decemal
ok LD (HL),A
LD HL,#6816 ;score_c
LD B,#06
cs_loop LD A,(HL)
INC HL
RST #10
DJNZ cs_loop
LD BC,#0F00 ;speed
delay DEC BC
LD A,B
OR C
JR NZ,delay
CALL #028E ;Call KEYSCAN
LD A,E
CP #09
JR Z,left
CP #10
JR Z,down
CP #11
JR Z,right
CP #12
JR NZ,loop
up LD DE,#FFE0
JR move
left LD DE,#FFFF
JR move
down LD DE,#0020
JR move
right LD DE,#0001
move LD HL,(#5C94) ;is player in wall?
LD A,H
OR L
JR Z,move_ok
ADD HL,DE
LD A,H
OR L
JR NZ,loop
move_ok LD HL,(#5C92)
LD A,(HL)
XOR #07
LD (HL),A
ADD HL,DE
LD A,(HL)
XOR #07
LD (HL),A
LD (#5C92),HL
LD HL,#0000
CP #38
JR Z,finish
LD H,D
LD L,E
finish LD (#5C94),HL ;Last move
LD HL,(#5C92)
LD DE,#58CB ;Square at center
LD A,#A7
LD (DE),A ;10100111 FL BR P2 P1 P0 I2 I1 I0
SBC HL,DE
RET Z
JP loop
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Learning Machine Code
DEFW is an assembler pseudoinstruciton that defines a word, that is a sixteen–bit-wide (i.e. two-byte) space. Different assemblers will treat its argument differently, if it’s not specified fully. In your case, DEFW #FF,#E0 actually means “write the following four bytes: $ff $00 $ef $00,” provided the assembler just fills out the unspecified byte with zeros.
What you probably want is to rewrite all those statements to read something like DEFW #FFE0, without the commas.
However, note that DEFW #FFE0 will probably store the data LSB-first, i.e. #E0 #FF, and not #FF #E0.
DEFB defines a byte, and DEFM is used by some assemblers to define a message (or string).
Most assemblers allow you use a comma to separate the arguments to save space:
DEFW #fd30,#e400,#21a0
DEFB 254,1,33,14
DEFM “string”, $20, “another string”
A lot of the times, the DEFB and DEFM statements are completely interchangeable.
There’s also DEFS, which defines (reserves) a space of a specific length and can (optionally) fill it with a specific value:
DEFS 30 $FE means, fill the next thirty bytes with the value $FE.
What you probably want is to rewrite all those statements to read something like DEFW #FFE0, without the commas.
However, note that DEFW #FFE0 will probably store the data LSB-first, i.e. #E0 #FF, and not #FF #E0.
DEFB defines a byte, and DEFM is used by some assemblers to define a message (or string).
Most assemblers allow you use a comma to separate the arguments to save space:
DEFW #fd30,#e400,#21a0
DEFB 254,1,33,14
DEFM “string”, $20, “another string”
A lot of the times, the DEFB and DEFM statements are completely interchangeable.
There’s also DEFS, which defines (reserves) a space of a specific length and can (optionally) fill it with a specific value:
DEFS 30 $FE means, fill the next thirty bytes with the value $FE.
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Re: Learning Machine Code
Oh my goodness I thought I had tried every combination... This works And it places the spiral at 0,0 which is where I was expecting it to beAst A. Moore wrote: ↑Sun Feb 16, 2020 2:38 pm DEFW is an assembler pseudoinstruciton that defines a word, that is a sixteen–bit-wide (i.e. two-byte) space. Different assemblers will treat its argument differently, if it’s not specified fully. In your case, DEFW #FF,#E0 actually means “write the following four bytes: $ff $00 $ef $00,” provided the assembler just fills out the unspecified byte with zeros.
Thank you so much.
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Learning Machine Code
Oh, a small optimization technique. Whenever possible, try avoiding the SBC HL,DE instruction. It takes 15 T states to execute and, unless you want it, requires that you clear the carry bit. What it does is it subtracts both DE and Carry from HL. If Carry is already zero, then it’s just a regular subtraction; if Carry is set, then an extra one will be subtracted from HL. So, if you don’t want that, you’ll have to precede it with an OR A—another 4 T states and an extra byte.
There’s no “subtract a 16-bit value without carry” instruction, unfortunately. However, there’s a workaround. If the value you want to subtract from HL is a constant, simply change its sign from “+” to “–” and use ADD HL,DE (only 11 T states).
So, instead of:
write this:
That, of course, depends on whether the assembler can understand this notation. Still, even if it can’t you can convert your number yourself by subtracting it from $10000.
There’s no “subtract a 16-bit value without carry” instruction, unfortunately. However, there’s a workaround. If the value you want to subtract from HL is a constant, simply change its sign from “+” to “–” and use ADD HL,DE (only 11 T states).
So, instead of:
Code: Select all
ld de,2343
or a
sbc hl,de
Code: Select all
ld de,-2343
add hl,de
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Re: Learning Machine Code
I have seen certain discussions on optimisation and T-states, for now I am focused on getting a broad understanding of the key terms and how to structure a program. Its quite tricky when yoiur limited to the few registers to create looping structures. In higher level languages I would just make/add variables as and when needed, but here its a careful balance.
It may seem like a small thing to you but I am so grateful for the reply as I dont have many friends learning 8bit machine code
Here is the finished product albeit still with the now not needed SET_C loop I added.
It may seem like a small thing to you but I am so grateful for the reply as I dont have many friends learning 8bit machine code
Here is the finished product albeit still with the now not needed SET_C loop I added.
Code: Select all
ORG 26621
JP start
score_1 DEFM #0D,"Your "
DEFM "score "
DEFM "now "
DEFM "999000" ;22 letters and spaces
score_c DEFM #16,#0B,#0F ;3
DEFM "000" ;3
spiral DEFW #FFE0
DEFW #A020
DEFW #AFA0
DEFW #A8A0
DEFW #AAA0
DEFW #AEA0
DEFW #A0A0
DEFW #BFA0
DEFW #8020
DEFW #FFE0;10
start XOR A
LD (#5C3C),A
LD B,#0A
LD HL,#681C ;address of spiral data
set_c LD C,#01
s_loop LD E,(HL)
INC HL
LD D,(HL)
INC HL
EX DE,HL
r_loop ADD HL,HL
JR C,wall
LD A,#3F
LD (#5C8F),A ;ATTR_T 0011 1111 FL BR P2 P1 P0 I2 I1 I0
JR prsq
wall LD A,#00
LD (#5C8F),A ;ATTR_T 0000 0000 FL BR P2 P1 P0 I2 I1 I0
prsq LD A,#2B ;+ character
RST #10
LD A,H
OR L
JR NZ,r_loop
EX DE,HL
LD A,C
DEC C
CP #01
JR NZ,s_loop
LD A,#0D ;return new line
RST #10
DJNZ set_c
LD A,#38
LD (#5821),A
LD A,#30
LD (#5C8F),A ;Black on yellow
LD HL,#6800 ;score_1
LD B,#15
sc_loop LD A,(HL)
INC HL
RST #10
DJNZ sc_loop
LD HL,#3939
LD (#6819),HL ;score_c +3
LD (#681A),HL ;score_c +4
LD HL,#5821
LD(#5C92),HL ;Store current position
LD HL,#0000
LD(#5C94),HL ;Store last move
loop LD HL,#681B ;Score_c + 5
decemal LD A,(HL)
CP #0F
JR NZ,positive
LD B,#03
reset INC HL
LD (HL),#30 ;"0"
DJNZ reset
RET
positive DEC A
CP #2F
JR NZ,ok
LD (HL),#39 ;"9"
DEC HL
JR decemal
ok LD (HL),A
LD HL,#6816 ;score_c
LD B,#06
cs_loop LD A,(HL)
INC HL
RST #10
DJNZ cs_loop
LD BC,#0F00 ;speed
delay DEC BC
LD A,B
OR C
JR NZ,delay
CALL #028E ;Call KEYSCAN
LD A,E
CP #09
JR Z,left
CP #10
JR Z,down
CP #11
JR Z,right
CP #12
JR NZ,loop
up LD DE,#FFE0
JR move
left LD DE,#FFFF
JR move
down LD DE,#0020
JR move
right LD DE,#0001
move LD HL,(#5C94) ;is player in wall?
LD A,H
OR L
JR Z,move_ok
ADD HL,DE
LD A,H
OR L
JR NZ,loop
move_ok LD HL,(#5C92)
LD A,(HL)
XOR #07
LD (HL),A
ADD HL,DE
LD A,(HL)
XOR #07
LD (HL),A
LD (#5C92),HL
LD HL,#0000
CP #38
JR Z,finish
LD H,D
LD L,E
finish LD (#5C94),HL ;Last move
LD HL,(#5C92)
LD DE,#5885 ;Square at center
LD A,#A7
LD (DE),A ;10100111 FL BR P2 P1 P0 I2 I1 I0
SBC HL,DE
RET Z
JP loop
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Learning Machine Code
You need to use labels properly, otherwise you’ll get confused by your own code in no time flat.
For example:
What if you want to move that data (and you will, if some other data comes before it)? Since you’ve already defined it (by assigning a label to it), just tell the assembler that:
The same goes for the rest of the data:
can be replaced with
and so on.
That way, you can move your actual data somewhere else in your code, say, append it to the end, and avoid the unnecessary JP start instruction. In addition, your ORG statement doesn’t have to be meticulously calculated each time. Just stick an easy to type number there, like 40000.
I haven’t looked at your code with any diligence, but the penultimate instruction is RET Z, right before a JP. I don’t see any CALLs in your code (aside from a single ROM CALL). Where exactly is you code supposed to return to once it gets there and the condition is true?
For example:
Code: Select all
LD HL,#681C ;address of spiral data
Code: Select all
LD HL,spiral
Code: Select all
LD (#6819),HL ;score_c +3
Code: Select all
LD (score_c+3),HL
That way, you can move your actual data somewhere else in your code, say, append it to the end, and avoid the unnecessary JP start instruction. In addition, your ORG statement doesn’t have to be meticulously calculated each time. Just stick an easy to type number there, like 40000.
I haven’t looked at your code with any diligence, but the penultimate instruction is RET Z, right before a JP. I don’t see any CALLs in your code (aside from a single ROM CALL). Where exactly is you code supposed to return to once it gets there and the condition is true?
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.