Click here to Skip to main content
15,119,116 members
Articles / Programming Languages / Assembler
Article
Posted 3 Oct 2020

Tagged as

Stats

9.1K views
270 downloads
11 bookmarked

A Z80 Assembler

Rate me:
Please Sign up or sign in to vote.
5.00/5 (14 votes)
3 Oct 2020CPOL2 min read
Back in 1984, I wanted to write a Z80 assembler. At the time, this would have meant coding it in Z80 machine code, but due to the conveniences of modern technology, I have now done it in C++.
A self contained Z80 assembler that can optionally write to a .sna file.

Implementation

I have, once again, used my own lexing and parsing libraries to implement the assembler. A typical rule looks something like this:

C++
g_map[grules.push("opcode", "LD '(' HL ')' ',' integer")] = [](data& data)
{
    data._memory.push_back(0x36);
    data.push_byte();
};

There are two modes to run the assembler in. If only a source file is supplied, then the source will be dumped back to std::cout complete with the opcodes, but if a template .sna and target pathname are supplied, then a new .sna is created which includes the assembled code.

For example, if your source looks like this:

ASM
ORG 23296 
LD IX, 16384
LD DE, 6912
CALL 1366
RET

Then the default output looks like this:

ASM
23296   221  33   0  64     LD IX, 16384
23300    17   0  27         LD DE, 6912
23303   205  86   5         CALL 1366
23306   201                 RET

Sample Assembly Source File

Here is a simple fill routine for the Sinclair ZX Spectrum:

ASM
  ORG 23298 
  LD BC, (23296)
  CALL GetScreenPos
Line:
  CALL FillLine
  CALL GetNextLine
  LD A, (HL)
  OR A
  JR Z, Line
  RET
FillLine:
  PUSH HL
  CALL FillLeft
  POP HL
  PUSH HL
  INC HL
  CALL FillRight
  POP HL
  RET
FillLeft:
  LD A, (HL)
  OR A
  JR NZ, MaskLeft
  LD (HL), 255
  DEC HL
  JR FillLeft
MaskLeft:
  LD B, 0
  PUSH AF
LeftAgain:
  BIT 0, A
  JR NZ, EndFillLeft
  SLA B
  SET 0, B
  SRA A
  JR LeftAgain
EndFillLeft:
  POP AF
  OR B
  LD (HL), A
  RET
FillRight:
  LD A, (HL)
  OR A
  JR NZ, MaskRight
  LD (HL), 255
  INC HL
  JR FillRight
MaskRight:
  LD B, 0
  PUSH AF
RightAgain:
  BIT 7, A
  JR NZ, EndFillRight
  SRA B
  SET 7, B
  SLA A
  JR RightAgain
EndFillRight:
  POP AF
  OR B
  LD (HL), A
  RET
GetScreenPos:
  LD A, C
  AND %00111000
  RLCA
  RLCA
  OR B
  LD L, A
  LD A, C
  AND %00000111
  LD H, A
  LD A, C
  AND %11000000
  RRCA
  RRCA
  RRCA
  OR H
  OR &40
  LD H, A
  RET
; Takes HL as Screen Address
GetNextLine:
  INC H
  LD A, H
  AND 7
  RET NZ
  LD A, L
  ADD A, 32
  LD L, A
  RET C
  LD A, H
  SUB 8
  LD H, A
  RET

and here is the driver in Sinclair Basic:

10 CIRCLE 125,100,50
14 POKE 23296,25
16 POKE 23297,15
20 RANDOMIZE USR 23298

Which produces:

Image 1

Using the Code

USAGE: z80_assembler <pathname> [<source .sna> <dest .sna>]

This is a work in progress, so be sure to report any issues.

History

  • 3rd October, 2020: Released
  • 3rd October, 2020: Added Z80 source example
  • 3rd October, 2020: Now dumping mnemonics with opcodes by default
  • 4th October, 2020: Now supporting integers as well as labels for CALL and JP
  • 4th October, 2020: Fixed rule integer: Hex;
  • 4th October, 2020: Fixed wlabel()
  • 5th October, 2020: Unrecognised disassembled opcodes now show as db nnn
  • 5th October, 2020: Correctly calculate the address if a label is on the same line as an opcode
  • 15th October, 2020: Now checking for running off the end of memory and simplified code generally.
  • 16th October, 2020: Fixed RST instruction.
  • 20th October, 2020: Added missing instructions.
  • 21st October, 2020: Added basic expression support and fixed a load of invalid indexes.
  • 21st October, 2020: Added '*', '/', '|' and '&' support as well as fixing more indexes.
  • 21st October, 2020: Added gcc Makefile.
  • 22nd October, 2020: Added undocumented instructions.
  • 24th October, 2020: Now allowing parenthesis in EQU, DB and DW expressions.
  • 10th January, 2020: Fixed DS/DEFS to work correctly. Took the disassembly of JSW and successfully assembled and ran it.
  • 16th January, 2020: Added tests for all instructions and fixed the disassembly of many instructions.
  • 17th January, 2020: Fixed DS directive, added missing whitespace in disassembler, added another test file.
  • 19th January, 2020: Added mnemonic verification to test code.
  • 2nd February, 2020: Assembler now records what type byte ranges are (code, db, dw, ds) to aid disassembly.
  • 3rd February, 2021: Always set offset in dump().
  • 3rd July, 2021: Updated parsertl.
  • 30th August, 2021: Introduced program struct.
  • 1st September, 2021: Evaluation order fix in disassem.cpp and clang warning fixes.
  • 2nd September, 2021: Fixed warnings when building with clang and -Wall.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ben Hanson
Software Developer (Senior)
United Kingdom United Kingdom
I started programming in 1983 using Sinclair BASIC, then moved on to Z80 machine code and assembler. In 1988 I programmed 68000 assembler on the ATARI ST and it was 1990 when I started my degree in Computing Systems where I learnt Pascal, C and C++ as well as various academic programming languages (ML, LISP etc.)

I have been developing commercial software for Windows using C++ since 1994.

Comments and Discussions

 
QuestionSome good memories there... Pin
ZimFromIRK6-Oct-20 7:28
MemberZimFromIRK6-Oct-20 7:28 
AnswerRe: Some good memories there... Pin
Ben Hanson6-Oct-20 11:08
MemberBen Hanson6-Oct-20 11:08 
AnswerRe: Some good memories there... Pin
colins27-Oct-20 4:44
Membercolins27-Oct-20 4:44 
QuestionCurious Pin
David Athersych5-Oct-20 9:11
MemberDavid Athersych5-Oct-20 9:11 
AnswerRe: Curious Pin
Ben Hanson5-Oct-20 12:01
MemberBen Hanson5-Oct-20 12:01 
GeneralRe: Curious Pin
David Athersych6-Oct-20 8:07
MemberDavid Athersych6-Oct-20 8:07 
GeneralRe: Curious Pin
Ben Hanson6-Oct-20 11:01
MemberBen Hanson6-Oct-20 11:01 
QuestionKudos, but I hated Z80 Assembler, the Motorola 6800 (and PDP Macro Assembly) were beautiful Pin
Kirk 103898215-Oct-20 7:03
MemberKirk 103898215-Oct-20 7:03 
AnswerRe: Kudos, but I hated Z80 Assembler, the Motorola 6800 (and PDP Macro Assembly) were beautiful Pin
unit150518-Nov-20 10:37
Memberunit150518-Nov-20 10:37 
PraiseHappy memories Pin
colins25-Oct-20 2:36
Membercolins25-Oct-20 2:36 
QuestionPete Shelley Said it Best Pin
Ben Hanson5-Oct-20 1:17
MemberBen Hanson5-Oct-20 1:17 
QuestionSuperb ! Pin
FenderBaba5-Oct-20 0:45
MemberFenderBaba5-Oct-20 0:45 
Thank You for sharing.
Decades ago, I did lot of gyms with Z80 Assembler Big Grin | :-D
Generalexcellent! Pin
Southmountain3-Oct-20 10:29
MemberSouthmountain3-Oct-20 10:29 
GeneralRe: excellent! Pin
Ben Hanson3-Oct-20 10:51
MemberBen Hanson3-Oct-20 10:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.