The Noob's Machine Code Thread

Anything QL Software or Programming Related.
Derek_Stewart
Font of All Knowledge
Posts: 3929
Joined: Mon Dec 20, 2010 11:40 am
Location: Sunny Runcorn, Cheshire, UK

Re: The Noob's Machine Code Thread

Post by Derek_Stewart »

Hi,

I would use QMAC Macro Assembler, which the best QL assembler, it will run on every QL platform.

The Z80 opcodes could be defined as Macros so that no change could be made to the Z80 code.

Most Z80 opcodes could defined in this way the Macros are drfined in a macro file included at the start of the assembley file.

For example:

Code: Select all

RET   MACRO
        RTS
      ENDM
which every occurance or RET would be replaced by RTS on assembley.


Regards,

Derek
User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: The Noob's Machine Code Thread

Post by NormanDunbar »

Assemblers!

I've never used the Computer 1 assembler, so I can't comment.

QMAC, is an excellent assembler for the MC68008 in the original QL, and for the higher spec processors, but you can only use MC68008 instructions, not the new stuff in the higher spec chips. Quite a steep learning curve with this one, you need to supply a command line with various options to assemble the code into CALLable or EXECable output files. I remember it taking me a few goes before I got the picture!

It's also good in that you can split your code into manageable chunks in different source files, assemble them separately, then use the supplied linker to amalgamate all the individual object files into the final binary.

GWASL, George Gwilt's excellent assembler, again for the 68008. Has a few foibles, cannot assemble SMSQ/E trap/vector/bit names due to them having a dot rather than an underscore. Doesn't like blank lines that contain spaces or tabs! Single file stuff only, unless you mess about with "IN flp1_myOtherFile_asm" type commands.

GWASS, George's other assembler. This one is for higher spec chips, and it doesn't have the problems GWASL has, as mentioned above. Can also do multi-file assemblies.

Talent, I've used it in as much as it is required by the SuperCharge/Turbo decompilers, but other than that, I'ts not one I'm familiar with.

Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
TMD2003
Trump Card
Posts: 168
Joined: Sat Oct 10, 2020 12:18 pm

Re: The Noob's Machine Code Thread

Post by TMD2003 »

Congraturation, I sucsess! I now have 168 bytes of 68008 machine code that does what I want it to do. It's very crude, that's for certain - though less crude than the ZX81 original. All I have yet to work out is how to make loops, as I have yet to find if there's an equivalent of INC, DEC and DJNZ (though in the case of the latter, I suspect not) - so for now, I've just written the instructions out as many times as I need them.

The results of my experiments should be released soon enough.


Spectribution: Dr. Jim's Sinclair computing pages.
Features my own programs, modified type-ins, RZXs, character sets & UDGs, and QL type-ins... so far!
User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: The Noob's Machine Code Thread

Post by NormanDunbar »

Inc = addq #1,d0
Dec = subq#1,d0

DJNZ is DBRA or DBF, same instruction. As in:

Code: Select all

    Move.w #count-1,d0
Loop
    Do something
    DBRA d0,loop
The loop ends when the count register is minus 1, not zero.

If you get the count from the user, or a calculation, than may result in zero, do this instead:

Code: Select all

    DoCalc or get user input into D0
    Bra.s endLoop
Loop
    Do stuff
EndLoop
    DBRA d0,loop
Cheers.
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
TMD2003
Trump Card
Posts: 168
Joined: Sat Oct 10, 2020 12:18 pm

Re: The Noob's Machine Code Thread

Post by TMD2003 »

Looking through your guide, it did occur to me that I might have to do an "add 1"/"sub 1" instruction for INC and DEC. It's good to know about the DBRA ending at -1 as well - at least I'd know to decrease the count from Z80 code by 1. Provided I remember, that is...

Anyway, this is what I've been making these last few days that led up to me making this thread in the first place:

Image Image

I'm thinking of making an official Illuminati Project where I convert one game to as many machines as I can. The QL is third in the list - after the ZX81 original that was entered for the comp.sys.sinclair Crap Games Competition in 2020, and the 16K Spectrum as part of Dave Hughes' annual WOOT! Tape Magazine at the end of last year. And it was specifically 16K - I set myself a challenge to package an improved version of the game (with colour and sound) into a machine that had around 6K less available memory.

Image Image
...the Spectrum version is showing off the glorious QL colours, out of six colour packages available.

The QL, even the smallest model, has no such concerns - so I thought I'd play to its strengths and beef up the graphics, as much as I could with the standard commands. Because the ZX81 original was so blocky (out of necessity), I saw no problem with using MODE 8, so I had to go all-out on using all the colours.

As a brief overview of the game, you have 16 attempts in which to "do a Wikileaks" on the Evil Lizard People's innermost secrets, by matching the hex code shown in the Evil Eye with the one that reaches the top of the Pyramid Of Power. You must enter three hex codes - which will propagate up the pyramid, according to the Illuminati's Top-Secret Calculation Formula. This, at the first attempt, was a DEFined FuNction written in SuperBASIC - but, as the ZX81 and Spectrum both used machine code to achieve this... "encryption", I thought it only right to do the same for the QL. Hence, I had to learn just enough 68008 opcodes so that the QL would perform the same job as the ZX81, in its own language.

If I do launch the Illuminati Project, this shouldn't be too hard to convert for other Z80 machines such as the Amstrad CPC, MSX series and Oric, even though I have barely one day's experience of programming the first and none at all of the other two. Still, it can't be hard, can it? Worryingly, though, my next target is... the VIC-20 (given a bit of extra memory). That would involve learning a limited amount of 6502 machine code, and I am led to believe it doesn't have quite as many registers to choose from as the Z80, let alone the 68008. Still, it'd be simple to make a C64 version from there.

The downloads are below - I've sent this game to Andy Jenkinson for the 2022 CSSCGC, but he says it's OK for me to post it here as well, where actual QL users will see it. It's designed for the original black-box QL - I wrote it with QemuLator, and if you're running it with QPC2 you'll have to find a way to slow it down to regular QL speed (which I am so far unaware of), and you'll need to change the LBYTES command to run with something other than mdv1_. Other than that I don't think there's anything that would stop it running under QPC2's S*BASIC (I always make sure to use END FOR instead of NEXT these days, for instance).

QLluminati.zip isn't a QL-zipped package, it's a regular ZIP - extract it as you would on a PC. There's a .MDV image for those who can still use that, and the game files ILV20_BAS and ILV20_BIN are held in the folder "files". Nobody here will need the loading instructions, that's just for QL noobs. The second package, files2.rar, is for those who really can't work out how the Illuminati's Top Secret Code works - or who can't be bothered to disassemble the machine code! ILV12_BAS is the final iteration of the SuperBASIC-only version of the program, which makes it a lot more obvious how it works, if you can untangle the line that performs the calculation. And if you're still stuck, there's a keygen program on there as well (which requires monitor mode).
Attachments
QLluminati.zip
(37.43 KiB) Downloaded 41 times
files2.rar
(7.61 KiB) Downloaded 41 times


Spectribution: Dr. Jim's Sinclair computing pages.
Features my own programs, modified type-ins, RZXs, character sets & UDGs, and QL type-ins... so far!
User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: The Noob's Machine Code Thread

Post by NormanDunbar »

Way Hey! Glad you got it all working. Well done.

I've not downloaded your game yet, I'm on QPC2 these days, so as you mention, it's probably a bit fast. I will have a look see later, when I get some time, though.

Regarding the 6502, well you are a wee bit restricted in registers there, definitely. You have the Accumulator, and the X and Y registers. That's about it really. Just to be sure, I checked:
wikipedia wrote: The 6502's registers include one 8-bit accumulator register (A), two 8-bit index registers (X and Y), 7 processor status flag bits (P; from bit 7 to bit 0 these are the negative (N), overflow (V), reserved, break (B), decimal (D), interrupt disable (I), zero (Z) and carry (C) flag), an 8-bit stack pointer (S), and a 16-bit program counter (PC).
Still, the Commodore C64 was based on the 6502, as was the BBC Micro, so it's all possible! Good luck.


Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
RalfR
Aurora
Posts: 870
Joined: Fri Jun 15, 2018 8:58 pm

Re: The Noob's Machine Code Thread

Post by RalfR »

I think, "DIR" can't work as a variable, because it is a keyword.

DEFine PROCedure zap_l(x%,y%,DIR,i%)


4E75 7000
User avatar
XorA
Site Admin
Posts: 1358
Joined: Thu Jun 02, 2011 11:31 am
Location: Shotts, North Lanarkshire, Scotland, UK

Re: The Noob's Machine Code Thread

Post by XorA »

Regarding the 6502, well you are a wee bit restricted in registers there, definitely. You have the Accumulator, and the X and Y registers. That's about it really. Just to be sure, I checked:
Thats why fast access to the zero page is essential on 6502 machines. It effectively acts as a 256 byte register bank!


User avatar
janbredenbeek
Super Gold Card
Posts: 629
Joined: Wed Jan 21, 2015 4:54 pm
Location: Hilversum, The Netherlands

Re: The Noob's Machine Code Thread

Post by janbredenbeek »

RalfR wrote:I think, "DIR" can't work as a variable, because it is a keyword.

DEFine PROCedure zap_l(x%,y%,DIR,i%)
That's what I thought too, until I tried it and it worked :)

Actually it's not a keyword but a built-in machinecode procedure. You cannot use it as a variable in the main program, but you can use it as a procedure parameter (and probably a LOCal variable too), because it's local to the procedure:

Code: Select all

DEFine PROCedure test(DIR)
  PRINT DIR
END DEFine test
Then try 'test 1' or even test 'hello' and it happily prints the given argument!
However, you cannot use the original DIR command within the procedure since it is replaced by the parameter, which is an ordinary variable now. This is the result of swapping the name table entry of the DIR procedure by the DIR variable for the duration of PROCedure test, as explained in Jan Jones's Definitive SuperBASIC handbook.


User avatar
tofro
Font of All Knowledge
Posts: 2685
Joined: Sun Feb 13, 2011 10:53 pm
Location: SW Germany

Re: The Noob's Machine Code Thread

Post by tofro »

janbredenbeek wrote:
RalfR wrote:I think, "DIR" can't work as a variable, because it is a keyword.

DEFine PROCedure zap_l(x%,y%,DIR,i%)
That's what I thought too, until I tried it and it worked :)

Actually it's not a keyword but a built-in machinecode procedure. You cannot use it as a variable in the main program, but you can use it as a procedure parameter (and probably a LOCal variable too), because it's local to the procedure:

Code: Select all

DEFine PROCedure test(DIR)
  PRINT DIR
END DEFine test
Then try 'test 1' or even test 'hello' and it happily prints the given argument!
However, you cannot use the original DIR command within the procedure since it is replaced by the parameter, which is an ordinary variable now. This is the result of swapping the name table entry of the DIR procedure by the DIR variable for the duration of PROCedure test, as explained in Jan Jones's Definitive SuperBASIC handbook.
The same thing works nicely with all in-built procedure and function names like PRINT or SIN - It doesn't work with operators or other keywords like INSTR, LET and FOR, for example (For logical reasons, as those don't live in the name table). This leads to the funny fact that in a procedure, you may legally write

Code: Select all

SIN (PI) = 1
and the interpreter won't even complain.


ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
Post Reply