I just finished getting through all the bugs I was having with my emacs mode. The mode will highlight all the z80 instructions in either all caps or all lowercase, highlights all the registers (unless I missed some, which would be easy to fix), colors numbers a special way ($FF, 0FFh, %11111111, 11111111b, and 255), colors the special $ that refers to the current position, colors the ./# preprocessor directives, colors labels, and it will auto-tab out your code. The last part means that if you start at the beginning and press tab on each line, it should (in most cases) tab it to the correct place. It will push out on pushes and in on pops. If you put a space on the line you are tabbing, it will let you go to whatever indentation level you want, and all the other code that follows will start at that indention. The way I've found to be useful for this is to just go to the beginning of your instruction ("ld" for instance), but a space before it, and tab to the correct indentation, and the press backspace to delete the space.

To use it, you copy the code below into a file (I called it z80-mode.el), and put it wherever you want (I put mine in ~/.emacs.d/), then you (load) the file in your .emacs file. For instance, the relevent line in my .emacs file looks like:
Code:
(load "~/.emacs.d/z80-mode.el")
The mode will automatically pick out .z80 files and work with them. To make a .asm file use this mode, you would do: M-x z80-mode RET. You could also change the line that looks like:
Code:
(add-to-list 'auto-mode-alist '("\\.z80\\'" . z80-mode))
to
Code:
(add-to-list 'auto-mode-alist '("\\.asm\\'" . z80-mode))
And it will pick out .asm files to work with, also.

That should be everything, so here is the code:

Code:
(defvar z80-mode-hook nil)
(defvar z80-mode-map
  (let ((map (make-keymap)))
    (define-key map "\C-j" 'newline-and-indent)
    (define-key map "\RET" 'newline-and-indent)
    map)
  "Keymap for z80 major mode")
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.z80\\'" . z80-mode))
(defconst z80-font-lock-keywords-1
  (list
   '("\\<\\(ADC\\|ADD\\|AND\\|BIT\\|CALL\\|CCF\\|CP\\|CPD\\|CPDR\\|CPIR\\|CPI\\|CPL\\|DAA\\|DEC\\|DI\\|DJNZ\\|EI\\|EX\\|EXX\\|HALT\\|IM\\|IN\\|INC\\|IND\\|INDR\\|INI\\|INIR\\|JP\\|JR\\|LD\\|LDD\\|LDDR\\|LDI\\|LDIR\\|NEG\\|NOP\\|MLT\\|OR\\|OTDM\\|OTDMR\\|OTDR\\|OTIM\\|OTIMR\\|OTIR\\|OUT\\|OUTD\\|OUTI\\|POP\\|PUSH\\|RES\\|RET\\|RETI\\|RETN\\|RL\\|RLA\\|RLC\\|RLCA\\|RLD\\|RR\\|RRA\\|RRC\\|RRCA\\|RRD\\|RST\\|SBC\\|SCF\\|SET\\|SLA\\|SLP\\|SRA\\|SRL\\|SUB\\|TST\\|TSTIO\\|XOR\\|adc\\|add\\|and\\|bit\\|call\\|ccf\\|cp\\|cpd\\|cpdr\\|cpir\\|cpi\\|cpl\\|daa\\|dec\\|di\\|djnz\\|ei\\|ex\\|exx\\|halt\\|im\\|in\\|inc\\|ind\\|indr\\|ini\\|inir\\|jp\\|jr\\|ld\\|ldd\\|lddr\\|ldi\\|ldir\\|neg\\|nop\\|mlt\\|or\\|otdm\\|otdmr\\|otdr\\|otim\\|otimr\\|otir\\|out\\|outd\\|outi\\|pop\\|push\\|res\\|ret\\|reti\\|retn\\|rl\\|rla\\|rlc\\|rlca\\|rld\\|rr\\|rra\\|rrc\\|rrca\\|rrd\\|rst\\|sbc\\|scf\\|set\\|sla\\|slp\\|sra\\|srl\\|sub\\|tst\\|tstio\\|xor\\|A\\|B\\|C\\|D\\|E\\|H\\|L\\|AF\\|BC\\|DE\\|HL\\|IX\\|IY\\|SP\\|PC\\|a\\|b\\|c\\|d\\|e\\|h\\|l\\|af\\|bc\\|de\\|hl\\|ix\\|iy\\|sp\\|pc\\|\\|NC\\|C\\|M\\|nc\\|c\\|m\\|Z\\|z\\|NZ\\|nz\\|\\|[Pp]\\([Oo]*\\|[Ee]*\\)\\|BCALL\\|bcall\\)\\>" . font-lock-builtin-face)
   '("\\(\\w*:\\)"  . font-lock-variable-name-face))
  "Minimal highlighting expressions for z80 mode")
(defconst z80-font-lock-keywords-2
  (append z80-font-lock-keywords-1
     (list
      '("\\<\\(\\([0-9][0-9A-Fa-f]*[Hh]\\|\\(0[Xx]\\|[0-9]\\|\\$[0-9A-Fa-f]\\)[0-9A-Fa-f]*\\)\\|[01][01]*[Bb]\\|%[01][01]*\\|[0-9]*\\)\\>" . font-lock-constant-face)
      '("\\(\\$\\)" . font-lock-function-name-face)))
  "Additional Keywords to highlight in z80 mode")
(defconst z80-font-lock-keywords-3
  (append z80-font-lock-keywords-2
     (list
      '("\\(\\.\\w*\\|#\\w*\\)" . font-lock-preprocessor-face)))
  "Balls-out highlighting in z80 mode")
(defvar z80-font-lock-keywords z80-font-lock-keywords-3
  "Default highlighting expressions for z80 mode")
(defun z80-indent-line ()
  "Indent current line as z80 code"
  (beginning-of-line)
  (let ((not-indented t) cur-indent)
    (if (looking-at "^\\w*:")
   (setq cur-indent 0)
      (if (looking-at "^[ \t]* [ \t]*")
     (setq cur-indent (+ (current-indentation) default-tab-width))
   (save-excursion
     (while not-indented
       (forward-line -1)
       (when (bobp)
         (setq not-indented nil)
         (setq cur-indent default-tab-width))
       (unless (or (looking-at "^[ \t]*$") (looking-at "^\\w*:")) ; Makes sure you aren't looking at blank lines or labels
         (if (looking-at "^[ \t]*[pP][oO][pP][ \t]")
        (progn
          (setq cur-indent (- (current-indentation) default-tab-width))
          (setq not-indented nil))
      (if (looking-at "^[ \t]*[pP][uU][Ss][Hh][ \t]")
          (progn
            (setq cur-indent (+ (current-indentation) default-tab-width))
            (setq not-indented nil))
        (when (looking-at "^[ \t][ \t]*\\w")
          (setq cur-indent (current-indentation))
          (setq not-indented nil)))))))))
    (if cur-indent
   (indent-line-to cur-indent)
      (indent-line-to 0)))) ; If we didn't see an indentation hint, then allow no indentation
(defvar z80-mode-syntax-table
  (let ((st (make-syntax-table)))
    (modify-syntax-entry ?_ "w" st)
    (modify-syntax-entry ?# "w" st)
    (modify-syntax-entry ?. "w" st)
    (modify-syntax-entry ?\; "<" st)
    (modify-syntax-entry ?\n ">" st)
    (modify-syntax-entry ?\t "-" st)
    st)
  "Syntax table for z80-mode")
(defun z80-mode ()
  "Major mode for editing Zilog Z80 ASM files"
  (interactive)
  (kill-all-local-variables)
  (set-syntax-table z80-mode-syntax-table)
  (use-local-map z80-mode-map)
  (set (make-local-variable 'font-lock-defaults) '(z80-font-lock-keywords))
  (set (make-local-variable 'indent-line-function) 'z80-indent-line) 
  (setq major-mode 'z80-mode)
  (setq mode-name "Z80")
  (run-hooks 'z80-mode-hook))
(provide 'z80-mode)
Looks great, Tanner. Smile
Wow, you did an extremely complete job on that! Did you submit it to ticalc.org, where I think it would be a good addition for those of us who still code with terminal text editors? If only I used emacs, I would totally use this, but I'm afraid my sanity insists on vim (in large part because that's what I learned as a fledgling Linux nublet). I hope this most of all helps you, though, so we can see more cool ASM programs from you soon!
I'm hoping it helps with my programming! If I get a chance, I'll upload this screenshot I took of your source code with highlighting and tabbing and such Very Happy (If it is fine with you, at least). And I actually hadn't thought of uploading it to TICalc.org, so I think I'll do that a little later today. I'll have some time later today to just program without the Internet, so I might actually get something done \o/
Vim is better.
Sorry for necroposting but I want to use this mode and continue to update it if possible:

This line:
Code:
(define-key map "\RET" 'newline-and-indent)

Should be

Code:
(define-key map (kbd "RET") 'newline-and-indent)

Otherwise you'll have a darn annoying time writing capital r (R)..

This is probably just a first update, more to come possibly.
Another thing I've noticed is that if you tab anywhere on a line, the thing that gets indented is the whole line instead of where you indent from, will try and change that too.
Regarding that last point, I'd prefer tabbing to indent the entire line if you're still typing the opcode and operand(s), but to insert a tab if you've finished writing the opcode and operand(s) and are tabbing over to add a comment. I don't know how feasible that is, though.
KermMartian wrote:
I'd prefer tabbing to indent the entire line if you're still typing the opcode and operand(s)

Yes, but if you want to align comments for example, that would be really annoying. And that's when you need it because with the mode, you indent correctly automatically.
Oh, yeah, another thing:
Macros/Variables shouldn't be indented, which they will be with this mode.

EDIT: I guess that last thing was unnecessary to comment on, I just commented (ugh, bad pun) the line with the ret (that I changed previously) out.
Now it won't do that anymore!
(Unenthusiastic) yay..
So now to figure out how to fix the "indent from start of the line" problem, then I'm calling it done..
I tried just commenting the line with (beginning-of-line) but that didn't really change much..

EDIT 2:
Ah, I went mad (insane) at a point so I deleted the indentation function from the z80-mode function, lo-and-behold.... it worked.
What the flippy-floppy..
So here's the final result if you don't want to have the mwim package, just comment out the two keymaps that uses is and the require for it, otherwise installit this way M-x Package-Install RET mwim RET

Code:
(require 'mwim)

(defvar z80-mode-hook nil)
(defvar z80-mode-map
  (let ((map (make-keymap)))
    (define-key map (kbd "C-j") 'newline-and-indent)
    ;;(define-key map (kbd "RET") 'newline-and-indent)
    (define-key map (kbd "C-a") 'mwim-beginning-of-code-or-line)
    (define-key map (kbd "C-e") 'mwim-end-of-code-or-line)
    map)
  "Keymap for z80 major mode")
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.z80\\'" . z80-mode))
(defconst z80-font-lock-keywords-1
  (list
   '("\\<\\(ADC\\|ADD\\|AND\\|BIT\\|CALL\\|CCF\\|CP\\|CPD\\|CPDR\\|CPIR\\|CPI\\|CPL\\|DAA\\|DEC\\|DI\\|DJNZ\\|EI\\|EX\\|EXX\\|HALT\\|IM\\|IN\\|INC\\|IND\\|INDR\\|INI\\|INIR\\|JP\\|JR\\|LD\\|LDD\\|LDDR\\|LDI\\|LDIR\\|NEG\\|NOP\\|MLT\\|OR\\|OTDM\\|OTDMR\\|OTDR\\|OTIM\\|OTIMR\\|OTIR\\|OUT\\|OUTD\\|OUTI\\|POP\\|PUSH\\|RES\\|RET\\|RETI\\|RETN\\|RL\\|RLA\\|RLC\\|RLCA\\|RLD\\|RR\\|RRA\\|RRC\\|RRCA\\|RRD\\|RST\\|SBC\\|SCF\\|SET\\|SLA\\|SLP\\|SRA\\|SRL\\|SUB\\|TST\\|TSTIO\\|XOR\\|adc\\|add\\|and\\|bit\\|call\\|ccf\\|cp\\|cpd\\|cpdr\\|cpir\\|cpi\\|cpl\\|daa\\|dec\\|di\\|djnz\\|ei\\|ex\\|exx\\|halt\\|im\\|in\\|inc\\|ind\\|indr\\|ini\\|inir\\|jp\\|jr\\|ld\\|ldd\\|lddr\\|ldi\\|ldir\\|neg\\|nop\\|mlt\\|or\\|otdm\\|otdmr\\|otdr\\|otim\\|otimr\\|otir\\|out\\|outd\\|outi\\|pop\\|push\\|res\\|ret\\|reti\\|retn\\|rl\\|rla\\|rlc\\|rlca\\|rld\\|rr\\|rra\\|rrc\\|rrca\\|rrd\\|rst\\|sbc\\|scf\\|set\\|sla\\|slp\\|sra\\|srl\\|sub\\|tst\\|tstio\\|xor\\|A\\|B\\|C\\|D\\|E\\|H\\|L\\|AF\\|BC\\|DE\\|HL\\|IX\\|IY\\|SP\\|PC\\|a\\|b\\|c\\|d\\|e\\|h\\|l\\|af\\|bc\\|de\\|hl\\|ix\\|iy\\|sp\\|pc\\|\\|NC\\|C\\|M\\|nc\\|c\\|m\\|Z\\|z\\|NZ\\|nz\\|\\|[Pp]\\([Oo]*\\|[Ee]*\\)\\|BCALL\\|bcall\\)\\>" . font-lock-builtin-face)
   '("\\(\\w*:\\)"  . font-lock-variable-name-face))
  "Minimal highlighting expressions for z80 mode")
(defconst z80-font-lock-keywords-2
  (append z80-font-lock-keywords-1
          (list
           '("\\<\\(\\([0-9][0-9A-Fa-f]*[Hh]\\|\\(0[Xx]\\|[0-9]\\|\\$[0-9A-Fa-f]\\)[0-9A-Fa-f]*\\)\\|[01][01]*[Bb]\\|%[01][01]*\\|[0-9]*\\)\\>" . font-lock-constant-face)
           '("\\(\\$\\)" . font-lock-function-name-face)))
  "Additional Keywords to highlight in z80 mode")
(defconst z80-font-lock-keywords-3
  (append z80-font-lock-keywords-2
          (list
           '("\\(\\.\\w*\\|#\\w*\\)" . font-lock-preprocessor-face)))
  "Balls-out highlighting in z80 mode")
(defvar z80-font-lock-keywords z80-font-lock-keywords-3
  "Default highlighting expressions for z80 mode")

(defvar z80-mode-syntax-table
  (let ((st (make-syntax-table)))
    (modify-syntax-entry ?_ "w" st)
    (modify-syntax-entry ?# "w" st)
    (modify-syntax-entry ?. "w" st)
    (modify-syntax-entry ?\; "<" st)
    (modify-syntax-entry ?\n ">" st)
    (modify-syntax-entry ?\t "-" st)
    st)
  "Syntax table for z80-mode")
(defun z80-mode ()
  "Major mode for editing Zilog Z80 ASM files"
  (interactive)
  (kill-all-local-variables)
  (set-syntax-table z80-mode-syntax-table)
  (use-local-map z80-mode-map)
  (set (make-local-variable 'font-lock-defaults) '(z80-font-lock-keywords))
  (setq major-mode 'z80-mode)
  (setq mode-name "Z80")
  (run-hooks 'z80-mode-hook))

(provide 'z80-mode)
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement